Skip to content

feat(observability): add reranker scores, streaming model fix, eval mode tracing#55

Merged
fvadicamo merged 6 commits into
developfrom
feat/pipeline-observability
Apr 9, 2026
Merged

feat(observability): add reranker scores, streaming model fix, eval mode tracing#55
fvadicamo merged 6 commits into
developfrom
feat/pipeline-observability

Conversation

@fvadicamo

@fvadicamo fvadicamo commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

What

  • DEBT-014: reranker scores for all evaluated candidates in QueryTrace
  • BUG-019: consistent llm_model between streaming and non-streaming traces
  • DEBT-015: rewritten query text in traces when VEKTRA_EVAL_MODE=true
  • DEBT-009: debug-level logging of rewritten queries when VEKTRA_DEBUG_LOG_QUERIES=true
  • FEAT-019: full prompt messages in traces when VEKTRA_EVAL_MODE=true

Why

Pipeline trace metadata was too sparse to diagnose RAG quality issues.
Reranker scores were discarded, rewritten queries invisible, streaming
reported wrong model names, and the actual prompt sent to the LLM was
never captured. These gaps forced re-running queries with temporary
debug code for every investigation.

Details

DEBT-014: reranker scores

  • rerank() returns RerankResult with top_k + all_scores for every evaluated candidate
  • needs_sigmoid detection now checks ALL candidates, not just top_k
  • Trace metadata includes chunk_id, reranker_score, original_score per candidate

BUG-019: streaming model name

  • Added model: str | None to CompletionChunk (backward-compatible)
  • LitellmProvider._stream_impl() captures chunk.model from first streaming chunk
  • Both pipelines read model from chunks instead of hardcoded config value

DEBT-015 + DEBT-009: eval_mode and debug logging plumbing

  • Added eval_mode and debug_log_queries to QueryPipelineConfig
  • Both pipelines store as instance vars (no constructor signature changes)
  • query_rewrite trace includes original/rewritten text when eval_mode=true
  • Debug log emits both texts at debug level when debug_log_queries=true

FEAT-019: prompt observability

  • build_prompt trace includes full messages list when eval_mode=true
  • Covers both execute() and _stream() in both pipelines

Checklist

  • All 5 items implemented
  • Tests written and passing (176 passed)
  • Lint clean (ruff check + format)
  • No constructor signature changes
  • GDPR: text capture gated on VEKTRA_EVAL_MODE only

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Optional eval and debug modes (VEKTRA_EVAL_MODE, VEKTRA_DEBUG_LOG_QUERIES) add richer trace metadata: original/rewritten queries, full prompt messages, per-candidate rerank diagnostics, and resolved LLM model attribution.
    • Reranking now returns full per-candidate scoring details alongside top-k results; streamed chunks include model info.
  • Bug Fixes

    • Streamed LLM chunks reliably report a resolved model for accurate trace attribution.
  • Tests

    • Updated and added tests for config, tracing, rerank, and streaming behaviors.

fvadicamo and others added 2 commits April 7, 2026 21:02
…val mode plumbing

DEBT-014: rerank() returns RerankResult with all_scores for every
evaluated candidate (not just top_k). Trace metadata now includes
per-chunk reranker and original scores for post-hoc threshold analysis.

BUG-019: capture resolved model name from litellm streaming chunks
via CompletionChunk.model field. Streaming and non-streaming traces
now report the same llm_model value.

DEBT-015: when VEKTRA_EVAL_MODE=true, query_rewrite StepTrace includes
original_query and rewritten_query text for diagnosing rewrite quality.

DEBT-009: when VEKTRA_DEBUG_LOG_QUERIES=true, _rewrite_query() emits
a debug-level structlog event with both original and rewritten text.

FEAT-019: when VEKTRA_EVAL_MODE=true, build_prompt StepTrace includes
the full messages list sent to the LLM for prompt inspection.

Both eval_mode and debug_log_queries are added to QueryPipelineConfig
(read from env vars), avoiding constructor changes to either pipeline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 4 tests for DEBT-015/FEAT-019 eval_mode gating:
- rewritten query captured in trace when eval_mode=True
- rewritten query excluded when eval_mode=False
- full prompt messages captured when eval_mode=True
- messages excluded when eval_mode=False

Fix H1: rename `os` loop variable to `orig` in rerank scores
comprehension to avoid shadowing the builtin.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fvadicamo fvadicamo added enhancement New feature or request component:shared vektra-shared component component:core vektra-core component labels Apr 7, 2026
@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d46ec223-9530-4763-a077-5b1afddfb99c

📥 Commits

Reviewing files that changed from the base of the PR and between 8ef3c76 and 09f14cb.

⛔ Files ignored due to path filters (1)
  • .s2s/BACKLOG.md is excluded by !.s2s/**
📒 Files selected for processing (1)
  • vektra-core/tests/test_advanced_pipeline.py

📝 Walkthrough

Walkthrough

Adds pipeline flags eval_mode and debug_log_queries; propagates resolved streamed LLM model into chunks and traces; changes reranker to return RerankResult with per-candidate scores; and enriches trace metadata for query rewrite, rerank, prompt build, and LLM streaming.

Changes

Cohort / File(s) Summary
Config & Types
vektra-shared/src/vektra_shared/config.py, vektra-shared/src/vektra_shared/types.py
Added eval_mode and debug_log_queries booleans to QueryPipelineConfig (env aliases VEKTRA_EVAL_MODE, VEKTRA_DEBUG_LOG_QUERIES) and added optional `model: str
Pipeline Tracing
vektra-core/src/vektra_core/pipeline.py, vektra-core/src/vektra_core/advanced_pipeline.py
Pipelines now read new flags; trace metadata for query_rewrite, rerank, build_prompt, and llm_stream conditionally include original/rewritten queries, messages when eval mode enabled, candidate counts/scores, and resolved LLM model. Debug logging of rewritten queries is optional via config.
Reranker
vektra-core/src/vektra_core/reranker.py
Introduced RerankResult dataclass; RerankerService.rerank now returns RerankResult(top_k, all_scores), evaluates all candidates, normalizes scores (sigmoid when needed), and records per-candidate (chunk_id, reranker_score, original_score).
Provider Streaming
vektra-core/src/vektra_core/providers/litellm_provider.py
Resolve a single model from the first received stream chunk (or requested model) and attach it to yielded CompletionChunks so streamed chunks consistently include model.
Tests
vektra-core/tests/..., vektra-shared/tests/*
Updated tests to expect RerankResult/all_scores, added eval-mode and debug-log trace assertions, added streaming model fallback tests, and added config parsing tests for new flags. (test_advanced_pipeline.py, test_reranker.py, test_litellm_provider.py, test_config.py)

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Pipeline as Pipeline
    participant Reranker as Reranker
    participant LLM as LLMProvider
    participant Tracer as Tracer

    Client->>Pipeline: execute(question)
    activate Pipeline

    Pipeline->>Tracer: emit query_rewrite step (rewritten?/original/rewrite)
    Pipeline->>Reranker: rerank(results, top_k)
    activate Reranker
    Reranker->>Reranker: evaluate all candidates -> all_scores
    Reranker-->>Pipeline: RerankResult(top_k, all_scores)
    deactivate Reranker

    Pipeline->>Tracer: emit rerank step (candidates_evaluated, scores)
    Pipeline->>Tracer: emit build_prompt step (messages when eval_mode)
    Pipeline->>LLM: stream(messages, model)
    activate LLM
    LLM->>LLM: resolve model from first chunk
    LLM-->>Pipeline: CompletionChunk(content, model)
    deactivate LLM

    Pipeline->>Tracer: emit llm_stream step (resolved model)
    Pipeline-->>Client: QueryTrace(steps, llm_model)
    deactivate Pipeline
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

bug

Poem

🐰 I hopped through traces, soft and spry,
Found models in the stream that fly,
Reranks counted every clue,
Eval mode showed both old and new,
Debug logs hop—hip, hop, hooray!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(observability): add reranker scores, streaming model fix, eval mode tracing' is directly related to the main changes: reranker now returns detailed scores, LLM streaming model is properly captured, and eval mode adds trace metadata.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/pipeline-observability

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an evaluation mode and debug logging to the query pipelines, enabling the capture of original/rewritten queries and full prompt messages within traces. It also refactors the reranker service to provide full score visibility for all candidates and enhances LLM model resolution during streaming. Feedback highlights a security violation regarding PII in debug logs, a recommendation to gate detailed reranker metadata behind the evaluation flag to avoid production trace bloat, and a logic improvement in the LiteLLM provider to correctly capture the model name from the stream.

Comment thread vektra-core/src/vektra_core/providers/litellm_provider.py
Comment thread vektra-core/src/vektra_core/advanced_pipeline.py
Comment thread vektra-core/src/vektra_core/advanced_pipeline.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
vektra-core/src/vektra_core/advanced_pipeline.py (1)

657-684: ⚠️ Potential issue | 🟡 Minor

Include model on failed llm_stream steps too.

The success path records the resolved model, but the exception path drops it from llm_stream metadata. Adding it there keeps failure traces just as actionable.

💡 Suggested change
             steps.append(
                 StepTrace(
                     name="llm_stream",
                     duration_ms=_elapsed_ms(t0),
-                    metadata={"error": str(exc)},
+                    metadata={"model": llm_model, "error": str(exc)},
                 )
             )

As per coding guidelines, vektra-core/**: RAG engine component. Check for QueryTrace completeness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/src/vektra_core/advanced_pipeline.py` around lines 657 - 684, The
exception branch for the llm_stream currently omits the resolved model in
StepTrace metadata; in the except block capture or default llm_model (use the
existing llm_model variable or self._llm_config.provider) and include it in the
StepTrace metadata alongside the error (e.g., metadata should contain both
"error": str(exc) and "model": llm_model) so failed llm_stream traces mirror the
success path; update the StepTrace creation in the except block accordingly
(symbols: llm_model, StepTrace, _llm_config.provider, stream exception block).
vektra-core/src/vektra_core/reranker.py (1)

58-63: ⚠️ Potential issue | 🟠 Major

Fix reranker mock return type in test_reranking_narrows_results().

Line 287 mocks reranker.rerank to return a bare list, but the caller reads .top_k and .all_scores attributes (lines 297 and 304 in advanced_pipeline.py). Change the return value to RerankResult(top_k=[results[2]], all_scores=[]) to match the new signature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/src/vektra_core/reranker.py` around lines 58 - 63, Update the
test mock in test_reranking_narrows_results so that reranker.rerank returns an
instance of RerankResult instead of a bare list: mock reranker.rerank to return
RerankResult(top_k=[results[2]], all_scores=[]) so the caller in
advanced_pipeline.py (which accesses .top_k and .all_scores) receives the
expected object; ensure the test imports or references the RerankResult type
used by reranker.rerank.
🧹 Nitpick comments (1)
vektra-core/src/vektra_core/pipeline.py (1)

503-517: Consider extracting prompt-trace metadata assembly into a shared helper.

build_meta and stream_build_meta are effectively duplicated; a helper would reduce drift between execute and streaming paths.

♻️ Suggested refactor
+def _build_prompt_trace_metadata(
+    prompt_version: str,
+    selected_chunks: int,
+    selected_history: int,
+    messages: list[Message],
+    eval_mode: bool,
+) -> dict[str, object]:
+    meta: dict[str, object] = {
+        "prompt_version": prompt_version,
+        "chunks_in_prompt": selected_chunks,
+        "history_turns_in_prompt": selected_history,
+    }
+    if eval_mode:
+        meta["messages"] = [{"role": m.role, "content": m.content} for m in messages]
+    return meta

Also applies to: 808-822

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/src/vektra_core/pipeline.py` around lines 503 - 517, The
prompt-trace metadata assembly is duplicated between build_meta and
stream_build_meta; extract this logic into a shared helper (e.g., a private
method like _assemble_prompt_meta) that takes the common inputs
(self._renderer.prompt_version, selected_chunks, selected_history, messages,
self._eval_mode and elapsed ms from t0) and returns the metadata dict; then
replace the inline build_meta and stream_build_meta constructions with calls to
that helper and reuse the resulting dict in the StepTrace creation in both
execute and streaming paths (references: build_meta, stream_build_meta,
StepTrace).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@vektra-core/src/vektra_core/advanced_pipeline.py`:
- Around line 657-684: The exception branch for the llm_stream currently omits
the resolved model in StepTrace metadata; in the except block capture or default
llm_model (use the existing llm_model variable or self._llm_config.provider) and
include it in the StepTrace metadata alongside the error (e.g., metadata should
contain both "error": str(exc) and "model": llm_model) so failed llm_stream
traces mirror the success path; update the StepTrace creation in the except
block accordingly (symbols: llm_model, StepTrace, _llm_config.provider, stream
exception block).

In `@vektra-core/src/vektra_core/reranker.py`:
- Around line 58-63: Update the test mock in test_reranking_narrows_results so
that reranker.rerank returns an instance of RerankResult instead of a bare list:
mock reranker.rerank to return RerankResult(top_k=[results[2]], all_scores=[])
so the caller in advanced_pipeline.py (which accesses .top_k and .all_scores)
receives the expected object; ensure the test imports or references the
RerankResult type used by reranker.rerank.

---

Nitpick comments:
In `@vektra-core/src/vektra_core/pipeline.py`:
- Around line 503-517: The prompt-trace metadata assembly is duplicated between
build_meta and stream_build_meta; extract this logic into a shared helper (e.g.,
a private method like _assemble_prompt_meta) that takes the common inputs
(self._renderer.prompt_version, selected_chunks, selected_history, messages,
self._eval_mode and elapsed ms from t0) and returns the metadata dict; then
replace the inline build_meta and stream_build_meta constructions with calls to
that helper and reuse the resulting dict in the StepTrace creation in both
execute and streaming paths (references: build_meta, stream_build_meta,
StepTrace).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 039573d0-678e-4eb7-adfb-1a3ca070e808

📥 Commits

Reviewing files that changed from the base of the PR and between a691778 and 00aaed8.

📒 Files selected for processing (10)
  • vektra-core/src/vektra_core/advanced_pipeline.py
  • vektra-core/src/vektra_core/pipeline.py
  • vektra-core/src/vektra_core/providers/litellm_provider.py
  • vektra-core/src/vektra_core/reranker.py
  • vektra-core/tests/test_advanced_pipeline.py
  • vektra-core/tests/test_litellm_provider.py
  • vektra-core/tests/test_reranker.py
  • vektra-shared/src/vektra_shared/config.py
  • vektra-shared/src/vektra_shared/types.py
  • vektra-shared/tests/test_config.py

- Gate reranker scores behind eval_mode to avoid trace bloat (Gemini #2)
- Add model to failed llm_stream StepTrace in both pipelines (CodeRabbit #4)
- Fix test_reranking_narrows_results mock to return RerankResult (CodeRabbit #5)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fvadicamo

Copy link
Copy Markdown
Contributor Author

Fixed in cf7162a. Both pipelines now include model in failed llm_stream StepTrace metadata. Addresses outside-diff comment on advanced_pipeline.py:657-684.

@fvadicamo

Copy link
Copy Markdown
Contributor Author

Fixed in cf7162a. test_reranking_narrows_results mock updated to return RerankResult. Addresses outside-diff comment on reranker.py:58-63.

@fvadicamo

Copy link
Copy Markdown
Contributor Author

Acknowledged. Two 6-line blocks don't justify a helper. The duplication is between execute() and _stream() which have different variable scoping; a helper would need to pass 5 parameters to save 4 lines. Keeping inline.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
vektra-core/tests/test_advanced_pipeline.py (2)

287-289: Populate all_scores in the rerank mock.

The pipeline’s new rerank trace metadata is driven by RerankResult.all_scores. Returning all_scores=[] only checks the signature change, not candidates_evaluated or the eval-mode scores projection, so an observability regression there would still pass.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/tests/test_advanced_pipeline.py` around lines 287 - 289, The
rerank mock currently returns RerankResult(top_k=[results[2]], all_scores=[])
which doesn't exercise the new rerank trace metadata; update the AsyncMock for
reranker.rerank to populate RerankResult.all_scores with realistic score entries
for the candidate set so tests exercise candidates_evaluated and the eval-mode
scores projection. Ensure the mocked all_scores length and order match the input
candidate list and include numeric score values so downstream logic that reads
RerankResult.all_scores (and the pipeline trace) is validated.

545-670: Add one streaming eval-mode case.

These tests lock down execute(), but this PR also changes _stream() to derive QueryTrace.llm_model from CompletionChunk.model and to carry eval-mode prompt messages in the trace. A single execute_stream() test with VEKTRA_EVAL_MODE=True and a chunk model would cover both new branches.

As per coding guidelines, vektra-core/** reviews should check streaming response handling and QueryTrace completeness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/tests/test_advanced_pipeline.py` around lines 545 - 670, Add a
new async test (e.g., test_eval_mode_stream_includes_prompt_and_model) that runs
the pipeline in streaming mode with pipeline_config set to VEKTRA_EVAL_MODE=True
and feeds an AsyncMock stream of CompletionChunk objects whose .model is set to
a known value; call the pipeline's execute_stream (or _stream) path to produce a
QueryTrace, then assert that trace.steps contains a "build_prompt" step with
"messages" in metadata and that the returned QueryTrace.llm_model equals the
CompletionChunk.model value; use the existing helpers (_make_pipeline,
_make_pipeline_config, _make_search_result) and AsyncMock chunks to simulate
streaming so the test covers both the prompt-messages branch and the chunk-model
assignment in _stream().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@vektra-core/src/vektra_core/advanced_pipeline.py`:
- Around line 164-176: The metadata dict for the query_rewrite StepTrace must
always include original_query and rewritten_query when self._eval_mode is True;
update all return paths in the query rewrite logic (the places that construct
metadata and return rewritten, StepTrace(...)) to set
metadata["original_query"]=question and metadata["rewritten_query"]=rewritten if
available, otherwise fall back to question for rewritten_query (e.g., when
rewrite was skipped or failed), ensuring StepTrace.metadata is stable across
success, skip, and error exits; reference the metadata dict,
StepTrace(name="query_rewrite", ...), original_hash, history, question, and
rewritten to locate where to add the fallback fields.

---

Nitpick comments:
In `@vektra-core/tests/test_advanced_pipeline.py`:
- Around line 287-289: The rerank mock currently returns
RerankResult(top_k=[results[2]], all_scores=[]) which doesn't exercise the new
rerank trace metadata; update the AsyncMock for reranker.rerank to populate
RerankResult.all_scores with realistic score entries for the candidate set so
tests exercise candidates_evaluated and the eval-mode scores projection. Ensure
the mocked all_scores length and order match the input candidate list and
include numeric score values so downstream logic that reads
RerankResult.all_scores (and the pipeline trace) is validated.
- Around line 545-670: Add a new async test (e.g.,
test_eval_mode_stream_includes_prompt_and_model) that runs the pipeline in
streaming mode with pipeline_config set to VEKTRA_EVAL_MODE=True and feeds an
AsyncMock stream of CompletionChunk objects whose .model is set to a known
value; call the pipeline's execute_stream (or _stream) path to produce a
QueryTrace, then assert that trace.steps contains a "build_prompt" step with
"messages" in metadata and that the returned QueryTrace.llm_model equals the
CompletionChunk.model value; use the existing helpers (_make_pipeline,
_make_pipeline_config, _make_search_result) and AsyncMock chunks to simulate
streaming so the test covers both the prompt-messages branch and the chunk-model
assignment in _stream().
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6c3111bc-d14f-4fd0-afbf-e3a2d5214d98

📥 Commits

Reviewing files that changed from the base of the PR and between 00aaed8 and cf7162a.

📒 Files selected for processing (3)
  • vektra-core/src/vektra_core/advanced_pipeline.py
  • vektra-core/src/vektra_core/pipeline.py
  • vektra-core/tests/test_advanced_pipeline.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • vektra-core/src/vektra_core/pipeline.py

Comment thread vektra-core/src/vektra_core/advanced_pipeline.py
@fvadicamo fvadicamo self-assigned this Apr 8, 2026
…aths

Add original_query and rewritten_query to skip and error paths in
_rewrite_query() when eval_mode is True. Previously only the success
path included these fields, making eval traces incomplete for skipped
or failed rewrites.

Also populate all_scores in test_reranking_narrows_results mock for
realistic trace metadata coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fvadicamo

Copy link
Copy Markdown
Contributor Author

Fixed in 0e4460c. test_reranking_narrows_results now populates all_scores with 3 candidate entries and asserts candidates_evaluated. Addresses nitpick on test_advanced_pipeline.py:287-289.

@fvadicamo

Copy link
Copy Markdown
Contributor Author

Acknowledged. The streaming path shares _build_prompt() with execute(), so eval_mode prompt capture is already tested. The model capture from chunks is tested in test_litellm_provider.py. A full streaming integration test would duplicate coverage without adding value. Addresses nitpick on test_advanced_pipeline.py:545-670.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
vektra-core/tests/test_advanced_pipeline.py (3)

303-305: Assert the rerank score payload, not just the count.

after_rerank and candidates_evaluated only verify cardinality. A regression that drops or misorders the emitted (chunk_id, reranker_score, original_score) entries would still pass here, so please assert the actual per-candidate trace list as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/tests/test_advanced_pipeline.py` around lines 303 - 305, The test
only checks counts via rerank_step.metadata["after_rerank"] and
["candidates_evaluated"], but must also assert the actual per-candidate payload
to detect dropped/misordered entries; update the assertions in
test_advanced_pipeline.py to fetch rerank_step = next(s for s in trace.steps if
s.name == "rerank") and assert rerank_step.metadata["after_rerank"] (or the
specific key that holds the list of emitted tuples) equals the expected list of
(chunk_id, reranker_score, original_score) in the correct order, and similarly
assert any per-candidate details in rerank_step.metadata["candidates_evaluated"]
if it contains structured entries rather than just a count.

553-641: Add eval_mode=True coverage for skipped and failed rewrites.

These tests only exercise the successful rewrite branch. The implementation change also adds original_query / rewritten_query in the no-history and exception paths, and those are the easiest places for content-gating regressions to slip through. Please add eval-mode variants of the skip and failure cases too.

Based on learnings, StepTrace.metadata is persisted verbatim to analytics and GDPR/no-user-content is enforced at the StepTrace source.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/tests/test_advanced_pipeline.py` around lines 553 - 641, Add two
new async tests mirroring the existing skip/failure branches but with
VEKTRA_EVAL_MODE=True: one for the "no-history" skip path and one for the
exception path. For each, reuse the test scaffolding (InMemoryConversationStore,
_make_pipeline, _make_pipeline_config, QueryRequest) but set
pipeline_config=_make_pipeline_config(VEKTRA_EVAL_MODE=True); for the skip case
ensure the rewrite step (step.name == "query_rewrite") has metadata["rewritten"]
set appropriately and includes both "original_query" and "rewritten_query" keys
with the expected values (original == input question); for the exception case
mock llm.complete to raise and assert the rewrite step metadata also contains
"original_query" and "rewritten_query" (and that rewritten indicates
failure/False as applicable). Reference existing test functions
test_eval_mode_captures_rewritten_query, _make_pipeline, and StepTrace metadata
when adding these two tests.

644-678: Mirror the prompt-metadata assertions in execute_stream().

FEAT-019 applies to streaming traces too, but this file only verifies the execute() path. Please add a streaming test that inspects the emitted trace chunk’s build_prompt step with eval mode on and off.

As per coding guidelines, vektra-core/**: check streaming response handling, QueryTrace completeness.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/tests/test_advanced_pipeline.py` around lines 644 - 678, Add
streaming equivalents of the two eval-mode tests that call
pipeline.execute_stream(...) and inspect the emitted trace chunk(s) for the
build_prompt step: create AsyncMock vector store results as in
test_eval_mode_captures_prompt_messages and
test_eval_mode_off_excludes_prompt_messages, build pipelines with _make_pipeline
and _make_pipeline_config(VEKTRA_EVAL_MODE=True/False), consume the stream to
obtain the trace object emitted (or the trace chunk containing build_prompt),
then assert for VEKT A_EVAL_MODE=True that build_prompt.metadata contains a
"messages" list with system and user roles and for False that "messages" is
absent; name the new tests e.g. test_eval_mode_captures_prompt_messages_stream
and test_eval_mode_off_excludes_prompt_messages_stream and reference
QueryRequest and build_prompt step when locating the trace in the stream.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@vektra-core/tests/test_advanced_pipeline.py`:
- Around line 303-305: The test only checks counts via
rerank_step.metadata["after_rerank"] and ["candidates_evaluated"], but must also
assert the actual per-candidate payload to detect dropped/misordered entries;
update the assertions in test_advanced_pipeline.py to fetch rerank_step = next(s
for s in trace.steps if s.name == "rerank") and assert
rerank_step.metadata["after_rerank"] (or the specific key that holds the list of
emitted tuples) equals the expected list of (chunk_id, reranker_score,
original_score) in the correct order, and similarly assert any per-candidate
details in rerank_step.metadata["candidates_evaluated"] if it contains
structured entries rather than just a count.
- Around line 553-641: Add two new async tests mirroring the existing
skip/failure branches but with VEKTRA_EVAL_MODE=True: one for the "no-history"
skip path and one for the exception path. For each, reuse the test scaffolding
(InMemoryConversationStore, _make_pipeline, _make_pipeline_config, QueryRequest)
but set pipeline_config=_make_pipeline_config(VEKTRA_EVAL_MODE=True); for the
skip case ensure the rewrite step (step.name == "query_rewrite") has
metadata["rewritten"] set appropriately and includes both "original_query" and
"rewritten_query" keys with the expected values (original == input question);
for the exception case mock llm.complete to raise and assert the rewrite step
metadata also contains "original_query" and "rewritten_query" (and that
rewritten indicates failure/False as applicable). Reference existing test
functions test_eval_mode_captures_rewritten_query, _make_pipeline, and StepTrace
metadata when adding these two tests.
- Around line 644-678: Add streaming equivalents of the two eval-mode tests that
call pipeline.execute_stream(...) and inspect the emitted trace chunk(s) for the
build_prompt step: create AsyncMock vector store results as in
test_eval_mode_captures_prompt_messages and
test_eval_mode_off_excludes_prompt_messages, build pipelines with _make_pipeline
and _make_pipeline_config(VEKTRA_EVAL_MODE=True/False), consume the stream to
obtain the trace object emitted (or the trace chunk containing build_prompt),
then assert for VEKT A_EVAL_MODE=True that build_prompt.metadata contains a
"messages" list with system and user roles and for False that "messages" is
absent; name the new tests e.g. test_eval_mode_captures_prompt_messages_stream
and test_eval_mode_off_excludes_prompt_messages_stream and reference
QueryRequest and build_prompt step when locating the trace in the stream.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dc092e04-cfcf-497b-831e-c5467266fa36

📥 Commits

Reviewing files that changed from the base of the PR and between cf7162a and 0e4460c.

📒 Files selected for processing (2)
  • vektra-core/src/vektra_core/advanced_pipeline.py
  • vektra-core/tests/test_advanced_pipeline.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • vektra-core/src/vektra_core/advanced_pipeline.py

…write paths

Cover the two rewrite paths that were missing eval_mode test coverage:
- skip path (no history): verify original_query and rewritten_query present
- error path (LLM failure): verify both fields present alongside error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fvadicamo

Copy link
Copy Markdown
Contributor Author

Won't fix: rerank scores are now gated behind eval_mode, so the non-eval test path correctly sees only counts. Per-candidate score assertions are already covered in test_reranker.py (test_all_scores_includes_items_beyond_top_k). Addresses nitpick on test_advanced_pipeline.py:303-305.

@fvadicamo

Copy link
Copy Markdown
Contributor Author

Fixed in 8ef3c76. Added test_eval_mode_skipped_rewrite_includes_query and test_eval_mode_failed_rewrite_includes_query. Addresses nitpick on test_advanced_pipeline.py:553-641.

@fvadicamo

Copy link
Copy Markdown
Contributor Author

Won't fix: AdvancedQueryPipeline._build_prompt() is a shared method used by both execute() and _stream(). eval_mode prompt capture is tested via execute(), which exercises the same code path. A streaming test would duplicate coverage without adding value. Addresses nitpick on test_advanced_pipeline.py:644-678.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
vektra-core/tests/test_advanced_pipeline.py (1)

702-736: Prompt metadata gating tests look good; consider one payload-shape assertion.

Optional hardening: assert at least one message has a non-empty "content" value to catch accidental role-only serialization regressions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vektra-core/tests/test_advanced_pipeline.py` around lines 702 - 736, In
test_eval_mode_captures_prompt_messages, add a payload-shape assertion that at
least one of the serialized messages has a non-empty "content" to catch
role-only serialization regressions (use the existing build_step/msgs
variables), e.g. assert any(msg.get("content") for msg in msgs) or equivalent;
do not change test_eval_mode_off_excludes_prompt_messages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@vektra-core/tests/test_advanced_pipeline.py`:
- Around line 702-736: In test_eval_mode_captures_prompt_messages, add a
payload-shape assertion that at least one of the serialized messages has a
non-empty "content" to catch role-only serialization regressions (use the
existing build_step/msgs variables), e.g. assert any(msg.get("content") for msg
in msgs) or equivalent; do not change
test_eval_mode_off_excludes_prompt_messages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 390bc720-c8af-4fc5-8eb2-883ae16e354a

📥 Commits

Reviewing files that changed from the base of the PR and between 0e4460c and 8ef3c76.

📒 Files selected for processing (1)
  • vektra-core/tests/test_advanced_pipeline.py

Mark 10 backlog items as completed with PR references:
- PR #53: BUG-013, DEBT-011
- PR #54: BUG-020, FEAT-020, DEBT-016
- PR #55: DEBT-014, BUG-019, DEBT-015, DEBT-009, FEAT-019

Also add content assertion to eval_mode prompt test per review.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fvadicamo

Copy link
Copy Markdown
Contributor Author

Fixed in 09f14cb. Added content assertion to test_eval_mode_captures_prompt_messages. Also updated backlog status for all 10 items completed across PRs #53-#55. Addresses nitpick on test_advanced_pipeline.py:702-736.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Apr 9, 2026
@fvadicamo
fvadicamo merged commit bf92d1a into develop Apr 9, 2026
19 checks passed
@fvadicamo
fvadicamo deleted the feat/pipeline-observability branch April 9, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component:core vektra-core component component:shared vektra-shared component documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant