Persist observed model provenance on learning lineage#357
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughModel/provider provenance is captured from LiteLLM and Claude Code responses, carried through tool loops, extraction, and generation services, persisted in SQLite lineage events, and returned by the learning provenance API. New lineage context and response schemas support optional provenance metadata. ChangesModel provenance and lineage
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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 `@reflexio/server/llm/_litellm_text_generation.py`:
- Around line 792-827: Update _configured_credential_label so the
custom_endpoint label is selected only when confirmed served-route metadata
identifies the custom endpoint, not merely when params["api_base"] matches it.
Preserve fallback attribution using the resolved provider/model route and ensure
network fallbacks do not inherit the primary custom endpoint credential label.
- Around line 1015-1016: Preserve the provenance computed by _call_and_parse
when parsing raises StructuredOutputParseError by attaching it to the exception
or converting the failure into a provenance-bearing _StructuredAttempt. Update
the first_error and exhausted-repair flows at the referenced call sites so
initial_provenance and final-attempt provenance remain populated even when every
parse attempt fails.
In `@reflexio/server/services/extraction/resumable_agent.py`:
- Around line 94-107: Update decode_committed_output so recognized version 1
envelopes never return committed_output as the payload when output is invalid or
model_provenance is missing. Extract and return the envelope’s output when
available, or use the appropriate existing error/fallback behavior when it is
missing or invalid, while preserving the legacy raw-payload path for
non-version-1 inputs.
In `@reflexio/server/services/playbook/components/consolidator.py`:
- Around line 751-755: Update the StructuredOutputRepairError handling around
first_parsed_output so the fallback is returned whenever that output exists,
even when provenance is absent. Track and assign the provenance belonging to the
attempt that produced first_parsed_output, rather than unconditionally using
initial_provenance; preserve the existing re-raise behavior when no parsed
output is available.
In `@reflexio/server/services/profile/components/consolidator.py`:
- Around line 612-617: Update the duplicate-group consolidation flow around
group_existing_indices and the merged_profile lineage mapping to track existing
indices already claimed by earlier groups. Before creating a merged profile and
recording lineage, skip or reject any group whose valid existing indices overlap
previously claimed indices; otherwise preserve the existing source filtering and
mapping behavior.
🪄 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 Plus
Run ID: 19b82651-5c00-4af6-ba6c-9dbad52405ec
📒 Files selected for processing (67)
reflexio/models/api_schema/domain/entities.pyreflexio/models/api_schema/retriever_schema.pyreflexio/models/api_schema/ui/converters.pyreflexio/models/api_schema/ui/entities.pyreflexio/models/config_schema.pyreflexio/server/README.mdreflexio/server/llm/__init__.pyreflexio/server/llm/_litellm_text_generation.pyreflexio/server/llm/_litellm_types.pyreflexio/server/llm/litellm_client.pyreflexio/server/llm/providers/claude_code_provider.pyreflexio/server/llm/providers/claude_code_stream_parser.pyreflexio/server/llm/tools.pyreflexio/server/routes/playbooks.pyreflexio/server/routes/profiles.pyreflexio/server/routes/provenance.pyreflexio/server/services/base_generation/_extraction_lifecycle.pyreflexio/server/services/base_generation_service.pyreflexio/server/services/deferred_learning_plan.pyreflexio/server/services/extraction/outcome.pyreflexio/server/services/extraction/resumable_agent.pyreflexio/server/services/extraction/resume_worker.pyreflexio/server/services/model_provenance.pyreflexio/server/services/playbook/components/aggregator.pyreflexio/server/services/playbook/components/consolidator.pyreflexio/server/services/playbook/components/extractor.pyreflexio/server/services/playbook/playbook_edit_apply.pyreflexio/server/services/playbook/service.pyreflexio/server/services/profile/components/consolidator.pyreflexio/server/services/profile/components/extractor.pyreflexio/server/services/profile/service.pyreflexio/server/services/reflection/components/extractor.pyreflexio/server/services/reflection/service.pyreflexio/server/services/storage/sqlite_storage/_base.pyreflexio/server/services/storage/sqlite_storage/_lineage.pyreflexio/server/services/storage/sqlite_storage/playbook/_agent.pyreflexio/server/services/storage/sqlite_storage/playbook/_user.pyreflexio/server/services/storage/sqlite_storage/profiles/_profile_store.pyreflexio/server/services/storage/storage_base/_lineage.pyreflexio/server/services/storage/storage_base/playbook/_agent.pyreflexio/server/services/storage/storage_base/playbook/_user.pyreflexio/server/services/storage/storage_base/profiles/_profile_store.pytests/models/test_lineage_models.pytests/models/test_llm_credential_labels.pytests/models/test_view_models.pytests/server/llm/test_claude_code_provider.pytests/server/llm/test_claude_code_stream_parser.pytests/server/llm/test_litellm_client_surface.pytests/server/llm/test_litellm_client_tool_calls.pytests/server/llm/test_litellm_client_unit.pytests/server/llm/test_tools.pytests/server/services/extraction/test_model_provenance_envelope.pytests/server/services/extraction/test_resumable_agent.pytests/server/services/playbook/test_cluster_change_detection.pytests/server/services/playbook/test_playbook_aggregator.pytests/server/services/playbook/test_playbook_consolidator.pytests/server/services/playbook/test_playbook_generation_service.pytests/server/services/profile/test_profile_generation_service.pytests/server/services/reflection/test_reflection_service.pytests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.pytests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.pytests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.pytests/server/services/storage/test_lineage_contract.pytests/server/services/storage/test_playbook_base_aggregate_emit.pytests/server/services/storage/test_sqlite_lineage_event_integration.pytests/server/test_app_route_inventory.pytests/server/test_lineage_events_api.py
There was a problem hiding this comment.
🧹 Nitpick comments (1)
reflexio/server/services/storage/storage_base/_lineage.py (1)
84-88: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse direct dictionary access instead of
setdefault.Since
resultis already pre-populated with all requestedentity_idsas keys on line 84, and theget_lineage_eventsquery guarantees that returned events belong to these IDs, you can use direct dictionary access. This is cleaner and provides a fail-fast mechanism (aKeyErrorwill be raised) if a faulty storage backend implementation ever returns unrequested entity IDs.♻️ Proposed refactor
- result = {entity_id: [] for entity_id in entity_ids} - for event in events: - if event.op not in CONTENT_SHAPING_LINEAGE_OPS: - continue - result.setdefault(event.entity_id, []).append(event) + result = {entity_id: [] for entity_id in entity_ids} + for event in events: + if event.op in CONTENT_SHAPING_LINEAGE_OPS: + result[event.entity_id].append(event)🤖 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 `@reflexio/server/services/storage/storage_base/_lineage.py` around lines 84 - 88, In the event aggregation loop, replace setdefault usage in the lineage result construction with direct access to the pre-populated result mapping, preserving the existing append behavior and allowing unexpected entity IDs to fail with KeyError.
🤖 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.
Nitpick comments:
In `@reflexio/server/services/storage/storage_base/_lineage.py`:
- Around line 84-88: In the event aggregation loop, replace setdefault usage in
the lineage result construction with direct access to the pre-populated result
mapping, preserving the existing append behavior and allowing unexpected entity
IDs to fail with KeyError.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 3f3357d0-fa35-465b-bb05-9741a3b6c483
📒 Files selected for processing (7)
reflexio/server/routes/provenance.pyreflexio/server/services/base_generation/_extraction_lifecycle.pyreflexio/server/services/base_generation_service.pyreflexio/server/services/storage/sqlite_storage/profiles/_profile_store.pyreflexio/server/services/storage/storage_base/_lineage.pytests/server/services/storage/test_lineage_contract.pytests/server/test_lineage_events_api.py
🚧 Files skipped from review as they are similar to previous changes (3)
- reflexio/server/services/base_generation_service.py
- reflexio/server/services/base_generation/_extraction_lifecycle.py
- reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py
Review — model provenance in learning lineageRead the full diff. The lineage/storage/schema plumbing is sound and well-tested. One correctness regression and a few simplification opportunities that speak to the size of this change. 1. Correctness — consolidator salvage path narrowed (high)
except StructuredOutputRepairError as exc:
if first_parsed_output is not None and exc.initial_provenance is not None:
self.model_provenance = exc.initial_provenance
return first_parsed_output
raise
except LiteLLMClientError:
raiseThis changes error behavior in two ways vs. the previous
Net: recoverable consolidations now fail, and the salvage decision is coupled to provenance capture, which is an unrelated concern. Suggest keeping the salvage unconditional on 2. Simplification — two parallel provenance-carrying mechanismsProvenance is threaded via both a wrapper type ( Relatedly, the unwrap block if isinstance(response, CompletionResult):
self.model_provenance = response.provenance
response = response.valueis copy-pasted in the profile consolidator, playbook consolidator, reflection extractor, and aggregator. 3. Simplification/robustness —
|
746b366 to
25b61dc
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
reflexio/server/services/playbook/components/consolidator.py (1)
751-761: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueCombine redundant exception handlers.
StructuredOutputRepairErroris a subclass ofLiteLLMClientErrorand both blocks execute identical fallback logic. You can safely remove theStructuredOutputRepairErrorblock to simplify the code.♻️ Proposed refactor
- except StructuredOutputRepairError as exc: - if first_parsed_output is not None: - self.model_provenance = exc.first_parsed_provenance - return first_parsed_output - raise except LiteLLMClientError as exc: if first_parsed_output is not None: self.model_provenance = exc.first_parsed_provenance return first_parsed_output raise🤖 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 `@reflexio/server/services/playbook/components/consolidator.py` around lines 751 - 761, Remove the redundant StructuredOutputRepairError handler and retain the existing fallback logic in the LiteLLMClientError handler. Ensure StructuredOutputRepairError continues to be caught through its LiteLLMClientError superclass, preserving model_provenance assignment, first_parsed_output return, and re-raising when no parsed output exists.
🤖 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 `@reflexio/server/llm/providers/claude_code_provider.py`:
- Line 646: The model response builders must always provide a string model,
falling back to the requested model when served_model is absent. In
reflexio/server/llm/providers/claude_code_provider.py:646-646, update
_build_model_response to use served_model or model; at :811-862, restore the
model: str parameter in _build_model_response_with_tool_call and apply the same
fallback; at :1051-1056, pass model=model to that helper invocation.
---
Nitpick comments:
In `@reflexio/server/services/playbook/components/consolidator.py`:
- Around line 751-761: Remove the redundant StructuredOutputRepairError handler
and retain the existing fallback logic in the LiteLLMClientError handler. Ensure
StructuredOutputRepairError continues to be caught through its
LiteLLMClientError superclass, preserving model_provenance assignment,
first_parsed_output return, and re-raising when no parsed output exists.
🪄 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 Plus
Run ID: 6d5cf08b-d184-4f4b-93a1-5af750478b47
📒 Files selected for processing (69)
reflexio/models/api_schema/domain/entities.pyreflexio/models/api_schema/retriever_schema.pyreflexio/models/api_schema/ui/converters.pyreflexio/models/api_schema/ui/entities.pyreflexio/models/config_schema.pyreflexio/server/README.mdreflexio/server/llm/__init__.pyreflexio/server/llm/_litellm_text_generation.pyreflexio/server/llm/_litellm_types.pyreflexio/server/llm/litellm_client.pyreflexio/server/llm/providers/claude_code_provider.pyreflexio/server/llm/providers/claude_code_stream_parser.pyreflexio/server/llm/tools.pyreflexio/server/routes/playbooks.pyreflexio/server/routes/profiles.pyreflexio/server/routes/provenance.pyreflexio/server/services/base_generation/_extraction_lifecycle.pyreflexio/server/services/base_generation_service.pyreflexio/server/services/deferred_learning_plan.pyreflexio/server/services/extraction/outcome.pyreflexio/server/services/extraction/resumable_agent.pyreflexio/server/services/extraction/resume_worker.pyreflexio/server/services/model_provenance.pyreflexio/server/services/playbook/components/aggregator.pyreflexio/server/services/playbook/components/consolidator.pyreflexio/server/services/playbook/components/extractor.pyreflexio/server/services/playbook/playbook_edit_apply.pyreflexio/server/services/playbook/service.pyreflexio/server/services/profile/components/consolidator.pyreflexio/server/services/profile/components/extractor.pyreflexio/server/services/profile/service.pyreflexio/server/services/reflection/components/extractor.pyreflexio/server/services/reflection/service.pyreflexio/server/services/storage/sqlite_storage/_base.pyreflexio/server/services/storage/sqlite_storage/_lineage.pyreflexio/server/services/storage/sqlite_storage/playbook/_agent.pyreflexio/server/services/storage/sqlite_storage/playbook/_user.pyreflexio/server/services/storage/sqlite_storage/profiles/_profile_store.pyreflexio/server/services/storage/storage_base/__init__.pyreflexio/server/services/storage/storage_base/_lineage.pyreflexio/server/services/storage/storage_base/playbook/_agent.pyreflexio/server/services/storage/storage_base/playbook/_user.pyreflexio/server/services/storage/storage_base/profiles/_profile_store.pytests/conftest.pytests/models/test_lineage_models.pytests/models/test_llm_credential_labels.pytests/models/test_view_models.pytests/server/llm/test_claude_code_provider.pytests/server/llm/test_claude_code_stream_parser.pytests/server/llm/test_litellm_client_surface.pytests/server/llm/test_litellm_client_tool_calls.pytests/server/llm/test_litellm_client_unit.pytests/server/llm/test_tools.pytests/server/services/extraction/test_model_provenance_envelope.pytests/server/services/extraction/test_resumable_agent.pytests/server/services/playbook/test_cluster_change_detection.pytests/server/services/playbook/test_playbook_aggregator.pytests/server/services/playbook/test_playbook_consolidator.pytests/server/services/playbook/test_playbook_generation_service.pytests/server/services/profile/test_profile_generation_service.pytests/server/services/reflection/test_reflection_service.pytests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.pytests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.pytests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.pytests/server/services/storage/test_lineage_contract.pytests/server/services/storage/test_playbook_base_aggregate_emit.pytests/server/services/storage/test_sqlite_lineage_event_integration.pytests/server/test_app_route_inventory.pytests/server/test_lineage_events_api.py
🚧 Files skipped from review as they are similar to previous changes (53)
- tests/models/test_llm_credential_labels.py
- reflexio/server/llm/init.py
- reflexio/server/services/model_provenance.py
- reflexio/server/services/storage/storage_base/playbook/_user.py
- reflexio/models/api_schema/domain/entities.py
- reflexio/server/services/storage/storage_base/init.py
- reflexio/server/services/base_generation/_extraction_lifecycle.py
- reflexio/server/services/playbook/playbook_edit_apply.py
- reflexio/server/services/base_generation_service.py
- reflexio/server/services/storage/storage_base/profiles/_profile_store.py
- tests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.py
- tests/server/services/playbook/test_playbook_generation_service.py
- tests/server/llm/test_litellm_client_tool_calls.py
- reflexio/server/services/reflection/components/extractor.py
- reflexio/server/routes/playbooks.py
- tests/models/test_lineage_models.py
- tests/server/llm/test_litellm_client_surface.py
- reflexio/server/llm/litellm_client.py
- reflexio/models/config_schema.py
- reflexio/server/routes/profiles.py
- reflexio/server/services/playbook/components/aggregator.py
- tests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.py
- reflexio/server/services/reflection/service.py
- tests/server/services/reflection/test_reflection_service.py
- reflexio/server/services/storage/storage_base/playbook/_agent.py
- tests/server/llm/test_tools.py
- reflexio/server/services/extraction/outcome.py
- reflexio/server/README.md
- reflexio/server/services/storage/storage_base/_lineage.py
- tests/server/services/playbook/test_playbook_aggregator.py
- tests/server/services/extraction/test_model_provenance_envelope.py
- reflexio/server/services/profile/components/consolidator.py
- reflexio/server/services/playbook/components/extractor.py
- reflexio/server/services/storage/sqlite_storage/playbook/_user.py
- tests/server/services/storage/test_playbook_base_aggregate_emit.py
- reflexio/server/services/profile/components/extractor.py
- reflexio/server/services/deferred_learning_plan.py
- tests/server/services/extraction/test_resumable_agent.py
- reflexio/server/services/storage/sqlite_storage/playbook/_agent.py
- tests/server/llm/test_claude_code_stream_parser.py
- tests/server/services/playbook/test_playbook_consolidator.py
- tests/server/services/playbook/test_cluster_change_detection.py
- reflexio/server/llm/tools.py
- reflexio/server/services/storage/sqlite_storage/_lineage.py
- tests/server/services/storage/test_lineage_contract.py
- tests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.py
- reflexio/server/services/storage/sqlite_storage/profiles/_profile_store.py
- reflexio/server/llm/providers/claude_code_stream_parser.py
- reflexio/server/services/playbook/service.py
- reflexio/server/services/profile/service.py
- reflexio/server/llm/_litellm_types.py
- reflexio/server/services/extraction/resume_worker.py
- reflexio/server/llm/_litellm_text_generation.py
6fcbad5 to
fbe181e
Compare
e79b3e2 to
119c13e
Compare
|
Addressed the review findings in the rebased branch (latest:
Verification details are refreshed in the PR body. @coderabbitai review |
|
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (2)
reflexio/server/services/storage/storage_base/playbook/_user.py (1)
42-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider validating
lineage_contextshere too, even though this fallback doesn't persist it.SQLite's override raises
ValueErrorfor length mismatches and non-"create"op_kind; this default silently swallows the same misuse viadel lineage_contexts. Backends that haven't overridden this method would mask a caller bug that only surfaces on SQLite.🤖 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 `@reflexio/server/services/storage/storage_base/playbook/_user.py` around lines 42 - 59, Validate lineage_contexts in save_user_playbooks_with_lineage before falling back to save_user_playbooks, matching SQLite’s ValueError behavior for length mismatches and any op_kind other than "create"; retain the existing fallback persistence after validation.reflexio/server/services/profile/components/extractor.py (1)
102-102: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd type annotation for consistency.
Sibling attributes on the same lines are explicitly typed (
_last_resumable_run_id: str | None = None,_last_resumable_token_totals: RunTokenTotals | None = None), but_last_model_provenanceis left untyped.♻️ Suggested annotation
- self._last_model_provenance = None + self._last_model_provenance: ModelProvenance | None = None🤖 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 `@reflexio/server/services/profile/components/extractor.py` at line 102, Add an explicit optional type annotation to _last_model_provenance in the extractor initialization, matching the annotations used by _last_resumable_run_id and _last_resumable_token_totals; preserve its existing None initialization.
🤖 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.
Nitpick comments:
In `@reflexio/server/services/profile/components/extractor.py`:
- Line 102: Add an explicit optional type annotation to _last_model_provenance
in the extractor initialization, matching the annotations used by
_last_resumable_run_id and _last_resumable_token_totals; preserve its existing
None initialization.
In `@reflexio/server/services/storage/storage_base/playbook/_user.py`:
- Around line 42-59: Validate lineage_contexts in
save_user_playbooks_with_lineage before falling back to save_user_playbooks,
matching SQLite’s ValueError behavior for length mismatches and any op_kind
other than "create"; retain the existing fallback persistence after validation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: f6337db0-3789-4b12-928a-b393b9d758a5
📒 Files selected for processing (57)
reflexio/models/api_schema/domain/entities.pyreflexio/models/api_schema/retriever_schema.pyreflexio/server/README.mdreflexio/server/llm/_litellm_text_generation.pyreflexio/server/llm/_litellm_types.pyreflexio/server/llm/providers/claude_code_provider.pyreflexio/server/llm/providers/claude_code_stream_parser.pyreflexio/server/llm/tools.pyreflexio/server/routes/provenance.pyreflexio/server/services/base_generation/_extraction_lifecycle.pyreflexio/server/services/base_generation_service.pyreflexio/server/services/deferred_learning_plan.pyreflexio/server/services/extraction/outcome.pyreflexio/server/services/extraction/resumable_agent.pyreflexio/server/services/extraction/resume_worker.pyreflexio/server/services/model_provenance.pyreflexio/server/services/playbook/components/aggregator.pyreflexio/server/services/playbook/components/consolidator.pyreflexio/server/services/playbook/components/extractor.pyreflexio/server/services/playbook/playbook_edit_apply.pyreflexio/server/services/playbook/service.pyreflexio/server/services/profile/components/consolidator.pyreflexio/server/services/profile/components/extractor.pyreflexio/server/services/profile/service.pyreflexio/server/services/storage/sqlite_storage/_base.pyreflexio/server/services/storage/sqlite_storage/_lineage.pyreflexio/server/services/storage/sqlite_storage/playbook/_agent.pyreflexio/server/services/storage/sqlite_storage/playbook/_user.pyreflexio/server/services/storage/sqlite_storage/profiles/_profile_store.pyreflexio/server/services/storage/storage_base/__init__.pyreflexio/server/services/storage/storage_base/playbook/_agent.pyreflexio/server/services/storage/storage_base/playbook/_user.pyreflexio/server/services/storage/storage_base/profiles/_profile_store.pytests/conftest.pytests/models/test_lineage_models.pytests/server/llm/test_claude_code_provider.pytests/server/llm/test_claude_code_stream_parser.pytests/server/llm/test_litellm_client_surface.pytests/server/llm/test_litellm_client_tool_calls.pytests/server/llm/test_litellm_client_unit.pytests/server/llm/test_tools.pytests/server/services/extraction/test_model_provenance_envelope.pytests/server/services/extraction/test_resumable_agent.pytests/server/services/playbook/test_cluster_change_detection.pytests/server/services/playbook/test_playbook_aggregator.pytests/server/services/playbook/test_playbook_consolidator.pytests/server/services/playbook/test_playbook_generation_service.pytests/server/services/playbook/test_playbook_generation_service_integration.pytests/server/services/profile/test_profile_generation_service.pytests/server/services/storage/sqlite_storage/test_create_lineage_provenance_integration.pytests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.pytests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.pytests/server/services/storage/test_lineage_write_capability.pytests/server/services/storage/test_playbook_base_aggregate_emit.pytests/server/services/storage/test_sqlite_lineage_event_integration.pytests/server/services/test_model_provenance.pytests/server/test_learning_provenance_api.py
🚧 Files skipped from review as they are similar to previous changes (29)
- tests/server/services/storage/test_sqlite_lineage_event_integration.py
- reflexio/models/api_schema/domain/entities.py
- reflexio/server/services/storage/storage_base/init.py
- reflexio/server/services/playbook/playbook_edit_apply.py
- reflexio/server/services/model_provenance.py
- reflexio/server/services/base_generation_service.py
- tests/server/llm/test_claude_code_stream_parser.py
- tests/models/test_lineage_models.py
- tests/server/services/storage/test_playbook_base_aggregate_emit.py
- tests/server/services/extraction/test_resumable_agent.py
- reflexio/server/services/extraction/outcome.py
- reflexio/server/services/playbook/components/extractor.py
- tests/conftest.py
- reflexio/server/services/storage/sqlite_storage/playbook/_agent.py
- tests/server/services/storage/sqlite_storage/test_save_agent_playbook_with_aggregate_event_integration.py
- reflexio/server/services/base_generation/_extraction_lifecycle.py
- reflexio/server/services/extraction/resumable_agent.py
- reflexio/server/services/storage/sqlite_storage/_base.py
- tests/server/services/storage/sqlite_storage/test_lineage_model_provenance_migration.py
- reflexio/server/llm/_litellm_types.py
- reflexio/server/services/profile/components/consolidator.py
- reflexio/server/llm/tools.py
- tests/server/services/playbook/test_cluster_change_detection.py
- tests/server/services/playbook/test_playbook_consolidator.py
- reflexio/server/services/profile/service.py
- reflexio/server/services/playbook/service.py
- reflexio/server/services/storage/storage_base/playbook/_agent.py
- reflexio/server/services/extraction/resume_worker.py
- reflexio/server/llm/_litellm_text_generation.py
Persist actual model_name and provider on new lineage_event rows for content-shaping writes. Capture only observed served metadata (not request-side LiteLLM routes). No public API expansion in this batch.
eaba95e to
dd25c1f
Compare
Summary
Persistence-only change. Capture the observed
model_nameandproviderthat actually served content-shaping LLM calls, and store them on new lineage events. This batch intentionally does not expand the public API surface.Developers who need the fields can query storage/
lineage_eventdirectly. A public read path can be added later when product need is clear (e.g. claude-smart local DB reader).Before
Learning lineage recorded what changed and which component changed it, but not which model route actually shaped a persisted profile or playbook.
Changed
model_nameandproviderfrom accepted completionscreatelineage when a caller supplies context; model fields may be nulllineage_eventrows only — no historical backfillModelResponse.modelstays the requested route string; provenance uses onlyreflexio_served_modelforclaude-coderoutesExplicit non-goals (this PR)
model_provenancefield onLearningProvenanceViewResponse/POST /api/get_learning_provenanceModelProvenanceViewpublic schemarequested_model, or credential/account labelAfter
lineage_event)model_name=MiniMax-M3,provider=minimaxmodel_name=…,provider=claude…Data flow
Verification
POST /api/get_learning_provenanceresponse keys excludemodel_provenanceFollow-ups (out of scope)