Skip to content

Conversation

@tisnik
Copy link
Contributor

@tisnik tisnik commented Oct 3, 2025

Description

LCORE-776: Allow started_at and completed_at timestamps to be store in database

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement

Related Tickets & Documents

  • Related Issue #LCORE-776

Summary by CodeRabbit

  • New Features

    • Conversation history now includes start and completion timestamps, providing clearer session timelines.
    • API responses for chat messages expose started_at and completed_at fields.
    • Timestamps are captured for both standard and streaming requests and persisted in conversation history.
  • Tests

    • Updated unit tests to validate presence and propagation of started_at and completed_at across endpoints and caches.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Walkthrough

Adds started_at and completed_at timestamps to conversation data: propagated from endpoints through utils to cache models and storage (Postgres/SQLite), exposed in conversations_v2 transformed messages, and covered by updated unit tests. SQL schemas and statements were extended; function signatures updated where necessary.

Changes

Cohort / File(s) Summary
Endpoints timestamps plumbing
src/app/endpoints/query.py, src/app/endpoints/streaming_query.py
Capture started_at at request start and completed_at after response; pass both into caching.
Message transformation
src/app/endpoints/conversations_v2.py
Transform output now includes started_at and completed_at from entries.
Cache model
src/models/cache_entry.py
CacheEntry adds public fields: started_at, completed_at.
Cache utils
src/utils/endpoints.py
store_conversation_into_cache signature extended; forwards timestamps into CacheEntry.
Postgres cache schema + IO
src/cache/postgres_cache.py
Table schema adds started_at, completed_at; SELECT/INSERT statements and mappings updated.
SQLite cache schema + IO
src/cache/sqlite_cache.py
Table schema adds started_at, completed_at; SELECT/INSERT statements and mappings updated.
Tests: endpoints
tests/unit/app/endpoints/test_conversations_v2.py
Expectations updated to include started_at and completed_at in transformed payload.
Tests: cache implementations
tests/unit/cache/test_noop_cache.py, tests/unit/cache/test_postgres_cache.py, tests/unit/cache/test_sqlite_cache.py
CacheEntry constructions updated with started_at and completed_at; assertions aligned with new schema.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant API as API Endpoint
  participant LLM as LLM Provider
  participant Cache as Cache Store

  User->>API: Send query
  API->>API: started_at = now()
  API->>LLM: Request completion
  LLM-->>API: Response
  API->>API: completed_at = now()
  API->>Cache: store(query, response, started_at, completed_at, metadata)
  Cache-->>API: ack
  API-->>User: Return response + ids
  note over API,Cache: Timestamps persisted with conversation
Loading
sequenceDiagram
  autonumber
  actor User
  participant API as Streaming Endpoint
  participant LLM as Streaming Provider
  participant Cache as Cache Store

  User->>API: Start streaming query
  API->>API: started_at = now()
  API->>LLM: Initiate stream
  LLM-->>API: Stream chunks
  API-->>User: Relay chunks (loop)
  API->>API: completed_at = now() (on stream end)
  API->>Cache: store(..., started_at, completed_at)
  Cache-->>API: ack
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

A tick, a tock, my whiskers twitch—
I log the start, I mark the switch.
From first hello to final byte,
Two timestamps glow in moonlit night.
Hop, cache, hop—the tale is told,
Begun and done, in time-stamped gold. 🐇⏱️

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly captures the main change of enabling started_at and completed_at timestamps to be stored in the database and references the associated ticket LCORE-776, making it clear and specific for anyone reviewing the project history.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

❤️ Share

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

Copy link
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: 0

Caution

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

⚠️ Outside diff range comments (2)
src/models/cache_entry.py (1)

6-21: Update the docstring to document the new timestamp fields.

The Attributes section in the docstring doesn't include started_at and completed_at, which are now part of the model.

Apply this diff to complete the documentation:

 class CacheEntry(BaseModel):
     """Model representing a cache entry.

     Attributes:
         query: The query string
         response: The response string
         provider: Provider identification
         model: Model identification
+        started_at: ISO 8601 timestamp when processing started (UTC with Z suffix)
+        completed_at: ISO 8601 timestamp when processing completed (UTC with Z suffix)
     """

     query: str
     response: str
     provider: str
     model: str
     started_at: str
     completed_at: str

Based on coding guidelines.

src/utils/endpoints.py (1)

184-217: Update the docstring to document new parameters.

The function signature was extended to include started_at and completed_at, but the docstring lacks an Args section describing these new parameters.

As per coding guidelines, apply this diff to add complete parameter documentation:

 def store_conversation_into_cache(
     config: AppConfig,
     user_id: str,
     conversation_id: str,
     provider_id: str,
     model_id: str,
     query: str,
     response: str,
     started_at: str,
     completed_at: str,
     _skip_userid_check: bool,
     topic_summary: str | None,
 ) -> None:
-    """Store one part of conversation into conversation history cache."""
+    """Store one part of conversation into conversation history cache.
+
+    Args:
+        config: Application configuration containing cache settings.
+        user_id: User identification.
+        conversation_id: Conversation ID unique for the given user.
+        provider_id: Model provider identifier.
+        model_id: Model identifier.
+        query: User query text.
+        response: Model response text.
+        started_at: ISO 8601 timestamp when the query processing started.
+        completed_at: ISO 8601 timestamp when the query processing completed.
+        _skip_userid_check: Skip user_id validation check.
+        topic_summary: Optional topic summary for the conversation.
+    """
🧹 Nitpick comments (2)
src/app/endpoints/conversations_v2.py (1)

241-252: Update docstring to document the new fields in the return value.

The function now returns started_at and completed_at fields, but the docstring doesn't document the complete structure of the returned dictionary.

Apply this diff to enhance the docstring:

 def transform_chat_message(entry: CacheEntry) -> dict[str, Any]:
-    """Transform the message read from cache into format used by response payload."""
+    """Transform the message read from cache into format used by response payload.
+    
+    Args:
+        entry: The cache entry containing query, response, and metadata.
+        
+    Returns:
+        A dictionary containing provider, model, messages list, started_at, and completed_at.
+    """
     return {

Based on coding guidelines.

src/cache/sqlite_cache.py (1)

22-40: Optional: Fix stale documentation.

The class docstring mentions "cache_key_key" UNIQUE CONSTRAINT, btree (key) which does not exist in the actual schema (there is no key column). This is a pre-existing documentation issue unrelated to the current changes.

Consider removing these lines from the docstring:

     Indexes:
         "cache_pkey" PRIMARY KEY, btree (user_id, conversation_id, created_at)
-        "cache_key_key" UNIQUE CONSTRAINT, btree (key)
         "timestamps" btree (updated_at)
-    Access method: heap
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f72b573 and 7b71c8b.

📒 Files selected for processing (11)
  • src/app/endpoints/conversations_v2.py (1 hunks)
  • src/app/endpoints/query.py (3 hunks)
  • src/app/endpoints/streaming_query.py (4 hunks)
  • src/cache/postgres_cache.py (5 hunks)
  • src/cache/sqlite_cache.py (5 hunks)
  • src/models/cache_entry.py (1 hunks)
  • src/utils/endpoints.py (2 hunks)
  • tests/unit/app/endpoints/test_conversations_v2.py (2 hunks)
  • tests/unit/cache/test_noop_cache.py (1 hunks)
  • tests/unit/cache/test_postgres_cache.py (1 hunks)
  • tests/unit/cache/test_sqlite_cache.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: All modules start with descriptive module-level docstrings explaining purpose
Use logger = logging.getLogger(name) for module logging after import logging
Define type aliases at module level for clarity
All functions require docstrings with brief descriptions
Provide complete type annotations for all function parameters and return types
Use typing_extensions.Self in model validators where appropriate
Use modern union syntax (str | int) and Optional[T] or T | None consistently
Function names use snake_case with descriptive, action-oriented prefixes (get_, validate_, check_)
Avoid in-place parameter modification; return new data structures instead of mutating arguments
Use appropriate logging levels: debug, info, warning, error with clear messages
All classes require descriptive docstrings explaining purpose
Class names use PascalCase with conventional suffixes (Configuration, Error/Exception, Resolver, Interface)
Abstract base classes should use abc.ABC and @AbstractMethod for interfaces
Provide complete type annotations for all class attributes
Follow Google Python docstring style for modules, classes, and functions, including Args, Returns, Raises, Attributes sections as needed

Files:

  • tests/unit/cache/test_postgres_cache.py
  • src/app/endpoints/conversations_v2.py
  • src/cache/sqlite_cache.py
  • src/app/endpoints/query.py
  • src/models/cache_entry.py
  • src/app/endpoints/streaming_query.py
  • tests/unit/app/endpoints/test_conversations_v2.py
  • tests/unit/cache/test_sqlite_cache.py
  • tests/unit/cache/test_noop_cache.py
  • src/utils/endpoints.py
  • src/cache/postgres_cache.py
tests/{unit,integration}/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/{unit,integration}/**/*.py: Use pytest for all unit and integration tests
Do not use unittest in tests; pytest is the standard

Files:

  • tests/unit/cache/test_postgres_cache.py
  • tests/unit/app/endpoints/test_conversations_v2.py
  • tests/unit/cache/test_sqlite_cache.py
  • tests/unit/cache/test_noop_cache.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Use pytest-mock to create AsyncMock objects for async interactions in tests
Use the shared auth mock constant: MOCK_AUTH = ("mock_user_id", "mock_username", False, "mock_token") in tests

Files:

  • tests/unit/cache/test_postgres_cache.py
  • tests/unit/app/endpoints/test_conversations_v2.py
  • tests/unit/cache/test_sqlite_cache.py
  • tests/unit/cache/test_noop_cache.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use absolute imports for internal modules (e.g., from auth import get_auth_dependency)

Files:

  • src/app/endpoints/conversations_v2.py
  • src/cache/sqlite_cache.py
  • src/app/endpoints/query.py
  • src/models/cache_entry.py
  • src/app/endpoints/streaming_query.py
  • src/utils/endpoints.py
  • src/cache/postgres_cache.py
src/app/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use standard FastAPI imports (from fastapi import APIRouter, HTTPException, Request, status, Depends) in FastAPI app code

Files:

  • src/app/endpoints/conversations_v2.py
  • src/app/endpoints/query.py
  • src/app/endpoints/streaming_query.py
src/{app/**/*.py,client.py}

📄 CodeRabbit inference engine (CLAUDE.md)

Use async def for I/O-bound operations and external API calls

Files:

  • src/app/endpoints/conversations_v2.py
  • src/app/endpoints/query.py
  • src/app/endpoints/streaming_query.py
src/app/endpoints/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

In API endpoints, raise FastAPI HTTPException with appropriate status codes for error handling

Files:

  • src/app/endpoints/conversations_v2.py
  • src/app/endpoints/query.py
  • src/app/endpoints/streaming_query.py
src/{models/**/*.py,configuration.py}

📄 CodeRabbit inference engine (CLAUDE.md)

src/{models/**/*.py,configuration.py}: Use @field_validator and @model_validator for custom validation in Pydantic models
Use precise type hints in configuration (e.g., Optional[FilePath], PositiveInt, SecretStr)

Files:

  • src/models/cache_entry.py
src/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/models/**/*.py: Pydantic models: use BaseModel for data models and extend ConfigurationBase for configuration
Use @model_validator and @field_validator for Pydantic model validation

Files:

  • src/models/cache_entry.py
🧬 Code graph analysis (3)
tests/unit/cache/test_postgres_cache.py (1)
src/models/cache_entry.py (1)
  • CacheEntry (6-21)
tests/unit/cache/test_sqlite_cache.py (1)
src/models/cache_entry.py (1)
  • CacheEntry (6-21)
tests/unit/cache/test_noop_cache.py (1)
src/models/cache_entry.py (1)
  • CacheEntry (6-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-pr
  • GitHub Check: e2e_tests
🔇 Additional comments (14)
tests/unit/cache/test_postgres_cache.py (1)

18-33: LGTM!

The test fixtures correctly include the new started_at and completed_at fields, aligning with the extended CacheEntry model. The ISO 8601 timestamp format with UTC 'Z' suffix is appropriate for storage.

src/app/endpoints/query.py (1)

244-244: LGTM!

The timestamps are captured at appropriate points in the request lifecycle:

  • started_at immediately after authentication
  • completed_at after LLM processing completes

The ISO 8601 format with second precision is suitable for this use case.

Also applies to: 334-344

tests/unit/app/endpoints/test_conversations_v2.py (1)

12-34: LGTM!

The test correctly validates that the transform_chat_message function includes the new timestamp fields in its output. The assertions verify both presence and values of started_at and completed_at.

src/app/endpoints/streaming_query.py (1)

600-600: LGTM!

The timestamps are captured at appropriate points in the streaming lifecycle:

  • started_at captured at the beginning of the handler
  • completed_at captured after streaming completes but before cache storage

The timestamp format is consistent with the non-streaming endpoint.

Also applies to: 724-734

tests/unit/cache/test_sqlite_cache.py (1)

20-35: LGTM!

The test fixtures correctly include the new timestamp fields, maintaining consistency with the updated CacheEntry model and other test files.

tests/unit/cache/test_noop_cache.py (1)

12-27: LGTM!

The test fixtures are correctly updated with the new timestamp fields, ensuring consistency across all cache implementation tests.

src/cache/sqlite_cache.py (4)

42-55: LGTM! Schema extension is correct.

The CREATE_CACHE_TABLE statement correctly adds started_at and completed_at as nullable text columns, consistent with the existing schema design.


72-83: LGTM! SQL statements correctly handle new fields.

Both SELECT_CONVERSATION_HISTORY_STATEMENT and INSERT_CONVERSATION_HISTORY_STATEMENT are properly updated to include started_at and completed_at in the correct positions.


210-220: LGTM! Data mapping is correct.

The get() method correctly maps the query results to CacheEntry fields, with started_at at index 4 and completed_at at index 5, matching the SELECT statement column order.


246-260: LGTM! Insert operation correctly passes timestamp fields.

The insert_or_append() method correctly extracts started_at and completed_at from the cache_entry and passes them to the INSERT statement in the correct parameter positions.

src/cache/postgres_cache.py (4)

38-51: LGTM! Schema extension is correct.

The CREATE_CACHE_TABLE statement correctly adds started_at and completed_at as nullable text columns, consistent with the SQLite implementation and existing schema design.


68-79: LGTM! SQL statements correctly handle new fields.

Both SELECT_CONVERSATION_HISTORY_STATEMENT and INSERT_CONVERSATION_HISTORY_STATEMENT properly include started_at and completed_at, with correct parameterization for PostgreSQL.


212-223: LGTM! Data mapping is correct.

The get() method correctly maps query results to CacheEntry fields, with started_at at index 4 and completed_at at index 5, matching the SELECT statement column order.


250-262: LGTM! Insert operation correctly passes timestamp fields.

The insert_or_append() method correctly extracts started_at and completed_at from the cache_entry and passes them to the INSERT statement in the correct parameter positions.

@tisnik tisnik merged commit 2ded492 into lightspeed-core:main Oct 3, 2025
18 of 19 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