-
Notifications
You must be signed in to change notification settings - Fork 9
LLM Chain: Base setup and interfaces created #581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| """add LLM_CHAIN job type | ||
| Revision ID: 045 | ||
| Revises: 044 | ||
| Create Date: 2026-02-04 00:35:43.891644 | ||
| """ | ||
| from alembic import op | ||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision = "045" | ||
| down_revision = "044" | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade(): | ||
| op.execute("ALTER TYPE jobtype ADD VALUE IF NOT EXISTS 'LLM_CHAIN'") | ||
|
|
||
|
|
||
| def downgrade(): | ||
| pass | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import logging | ||
|
|
||
| from fastapi import APIRouter, Depends | ||
|
|
||
| from app.api.deps import AuthContextDep, SessionDep | ||
| from app.api.permissions import Permission, require_permission | ||
| from app.models import LLMChainRequest, Message | ||
| from app.services.llm.chain_executor import start_chain_job | ||
| from app.utils import APIResponse, validate_callback_url | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| router = APIRouter(tags=["llm"]) | ||
|
|
||
|
|
||
| @router.post( | ||
| "/llm/chain", | ||
| response_model=APIResponse[Message], | ||
| dependencies=[Depends(require_permission(Permission.REQUIRE_PROJECT))], | ||
| ) | ||
| def llm_chain( | ||
| _current_user: AuthContextDep, _session: SessionDep, request: LLMChainRequest | ||
| ): | ||
|
Comment on lines
+21
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "llm_chain.py" -type f | grep -E "backend/app/api"Repository: ProjectTech4DevAI/kaapi-backend Length of output: 112 🏁 Script executed: head -50 backend/app/api/routes/llm_chain.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 1231 🏁 Script executed: wc -l backend/app/api/routes/llm_chain.pyRepository: ProjectTech4DevAI/kaapi-backend Length of output: 113 Add a return type hint for The function is missing a return type annotation. Since the decorator specifies -def llm_chain(
- _current_user: AuthContextDep, _session: SessionDep, request: LLMChainRequest
-):
+def llm_chain(
+ _current_user: AuthContextDep, _session: SessionDep, request: LLMChainRequest
+) -> APIResponse[Message]:As per coding guidelines: Always add type hints to all function parameters and return values in Python code. 🤖 Prompt for AI Agents |
||
| project_id = _current_user.project_.id | ||
| organization_id = _current_user.organization_.id | ||
|
|
||
| if request.callback_url: | ||
| validate_callback_url(str(request.callback_url)) | ||
|
|
||
| start_chain_job( | ||
| db=_session, | ||
| request=request, | ||
| project_id=project_id, | ||
| organization_id=organization_id, | ||
| ) | ||
|
|
||
| return APIResponse.success_response( | ||
| data=Message( | ||
| message="Chain execution started. Results will be delivered via callback." | ||
| ) | ||
| ) | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from sqlmodel import Field, SQLModel | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pydantic import Discriminator, model_validator, HttpUrl | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Dict | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class KaapiLLMParams(SQLModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -120,10 +122,17 @@ class KaapiCompletionConfig(SQLModel): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class PromptTemplateConfig(SQLModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| template: str = Field(..., description="prompt template") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class ConfigBlob(SQLModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Raw JSON blob of config.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| completion: CompletionConfig = Field(..., description="Completion configuration") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prompt_template: PromptTemplateConfig | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, description="optional prompt template" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Future additions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # classifier: ClassifierConfig | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # pre_filter: PreFilterConfig | None = None | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -223,3 +232,210 @@ class LLMCallRequest(SQLModel): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "The exact dictionary provided here will be returned in the response metadata field." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class ChainBlock(SQLModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config: LLMCallConfig = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ..., description="LLM call configuration for this block" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| intermediate_callback: bool = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description="Optional callback URL for intermediary results after this block completes", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| include_provider_raw_response: bool = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description="Whether to include the raw LLM provider response in the output", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| request_metadata: dict[str, Any] | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description=( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Client-provided metadata passed through unchanged in the response. " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Use this to correlate responses with requests or track request state. " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "The exact dictionary provided here will be returned in the response metadata field." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class LLMChainRequest(SQLModel): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # query | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| query: QueryParams = Field(..., description="Query-specific parameters") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # blocks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| blocks: list[ChainBlock] = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ..., min_length=1, description="Ordered list of blocks to execute" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # callback_url | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| callback_url: HttpUrl | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, description="Webhook URL for async response delivery" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class LlmCall(SQLModel, table=True): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Database model for tracking LLM API call requests and responses. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Stores both request inputs and response outputs for traceability, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| supporting multimodal inputs (text, audio, image) and various completion types. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| __tablename__ = "llm_call" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| __table_args__ = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Index( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "idx_llm_call_job_id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "job_id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postgresql_where=text("deleted_at IS NULL"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Index( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "idx_llm_call_conversation_id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "conversation_id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| postgresql_where=text("conversation_id IS NOT NULL AND deleted_at IS NULL"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+275
to
+295
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Missing imports cause The 🐛 Proposed fix: Add missing imports at the top of the file from typing import Annotated, Any, Literal, Union
from uuid import UUID
+from uuid import uuid4
+from datetime import datetime
+
+import sqlalchemy as sa
+from sqlalchemy import Index, text
+from sqlalchemy.dialects.postgresql import JSONB
from sqlmodel import Field, SQLModel
from pydantic import Discriminator, model_validator, HttpUrl
-from typing import Dict
+from app.core.util import now📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Actions: Kaapi CI[error] 285-285: NameError: name 'Index' is not defined 🪛 Ruff (0.14.14)[error] 285-285: Undefined name (F821) [error] 288-288: Undefined name (F821) [error] 290-290: Undefined name (F821) [error] 293-293: Undefined name (F821) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: UUID = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default_factory=uuid4, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| primary_key=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={"comment": "Unique identifier for the LLM call record"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| job_id: UUID = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreign_key="job.id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ondelete="CASCADE", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "Reference to the parent job (status tracked in job table)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| project_id: int = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreign_key="project.id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ondelete="CASCADE", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "Reference to the project this LLM call belongs to" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| organization_id: int = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foreign_key="organization.id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ondelete="CASCADE", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "Reference to the organization this LLM call belongs to" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Request fields | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| input: str = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ..., | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "User input - text string, binary data, or file path for multimodal" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| input_type: Literal["text", "audio", "image"] = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ..., | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column=sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa.String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment="Input type: text, audio, image", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| output_type: Literal["text", "audio", "image"] | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column=sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa.String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment="Expected output type: text, audio, image", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Provider and model info | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| provider: str = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ..., | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column=sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa.String, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment="AI provider as sent by user (e.g openai, -native, google)", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| model: str = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ..., | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "Specific model used e.g. 'gpt-4o', 'gemini-2.5-pro'" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Response fields | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| provider_response_id: str | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "Original response ID from the provider (e.g., OpenAI's response ID)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: dict[str, Any] | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column=sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JSONB, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment="Response content: {text: '...'}, {audio_bytes: '...'}, or {image: '...'}", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| usage: dict[str, Any] | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column=sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JSONB, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment="Token usage: {input_tokens, output_tokens, reasoning_tokens}", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Conversation tracking | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| conversation_id: str | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "Identifier linking this response to its conversation thread" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auto_create: bool | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "comment": "Whether to auto-create conversation if conversation_id doesn't exist (OpenAI specific)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Configuration - stores either {config_id, config_version} or {config_blob} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config: dict[str, Any] | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column=sa.Column( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JSONB, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| comment="Configuration: {config_id, config_version} for stored config OR {config_blob} for ad-hoc config", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Timestamps | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| created_at: datetime = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default_factory=now, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={"comment": "Timestamp when the LLM call was created"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| updated_at: datetime = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default_factory=now, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={"comment": "Timestamp when the LLM call was last updated"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| deleted_at: datetime | None = Field( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nullable=True, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sa_column_kwargs={"comment": "Timestamp when the record was soft-deleted"}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: ProjectTech4DevAI/kaapi-backend
Length of output: 135
🏁 Script executed:
Repository: ProjectTech4DevAI/kaapi-backend
Length of output: 591
🏁 Script executed:
Repository: ProjectTech4DevAI/kaapi-backend
Length of output: 4173
Migration files lack type hints across the codebase.
The
upgrade()anddowngrade()functions should include explicit return type hints (-> None) per coding guidelines. This is a codebase-wide issue affecting all migration files (001–045), not limited to this revision. Consider adding type hints to all migration functions for consistency.🤖 Prompt for AI Agents