feat(backends,storage,core,markdown,infra): claude agent sdk backend, session store, transcript seeding, runner isolation
This commit is contained in:
1 parent
ee2dc918ee
commit
e1f242a87a
28 files changed
+2154
-875
No files matched your search
@@ -23,8 +23,10 @@ needs an id uses ``Optional[int]`` so SQLAlchemy can autoincrement.
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import UniqueConstraint
|
||||
from sqlalchemy import JSON, Column, Index, UniqueConstraint, text
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
|
||||
@@ -92,6 +94,7 @@ class Conversation(SQLModel, table=True):
|
||||
frontend: str = Field(index=True)
|
||||
external_id: str = Field(index=True)
|
||||
agent_name: str = Field(index=True)
|
||||
session_id: str | None = Field(default=None, index=True)
|
||||
created_at: datetime = Field(default_factory=_utcnow)
|
||||
updated_at: datetime = Field(default_factory=_utcnow)
|
||||
|
||||
@@ -125,4 +128,73 @@ class ConversationMessage(SQLModel, table=True):
|
||||
created_at: datetime = Field(default_factory=_utcnow)
|
||||
|
||||
|
||||
__all__ = ["AuditLog", "Conversation", "ConversationMessage", "Token"]
|
||||
class TranscriptEntry(SQLModel, table=True):
|
||||
"""One Agent SDK transcript line, mirrored from the session store protocol.
|
||||
|
||||
``(project_key, session_id, subpath)`` is the ``SessionKey``; ``subpath``
|
||||
is ``""`` for the main transcript so the unique constraints stay simple.
|
||||
``uuid`` is the SDK's idempotency key - the partial unique index rejects
|
||||
a replayed batch, entries without a uuid are appended as-is.
|
||||
"""
|
||||
|
||||
__tablename__ = "transcript_entries"
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"project_key", "session_id", "subpath", "seq", name="uq_transcript_seq"
|
||||
),
|
||||
Index(
|
||||
"uq_transcript_uuid",
|
||||
"project_key",
|
||||
"session_id",
|
||||
"subpath",
|
||||
"uuid",
|
||||
unique=True,
|
||||
postgresql_where=text("uuid IS NOT NULL"),
|
||||
sqlite_where=text("uuid IS NOT NULL"),
|
||||
),
|
||||
)
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
project_key: str = Field(index=True)
|
||||
session_id: str = Field(index=True)
|
||||
subpath: str = Field(default="")
|
||||
seq: int
|
||||
uuid: str | None = Field(default=None)
|
||||
entry: dict[str, Any] = Field(
|
||||
sa_column=Column(JSON().with_variant(JSONB(), "postgresql"), nullable=False)
|
||||
)
|
||||
origin: str | None = Field(default=None)
|
||||
source: str | None = Field(default=None)
|
||||
turn_id: str | None = Field(default=None)
|
||||
created_at: datetime = Field(default_factory=_utcnow)
|
||||
|
||||
|
||||
class Usage(SQLModel, table=True):
|
||||
"""Per-turn token accounting from ``ResultMessage.usage``."""
|
||||
|
||||
__tablename__ = "usage"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
ts: datetime = Field(default_factory=_utcnow, index=True)
|
||||
agent_name: str = Field(index=True)
|
||||
conversation_id: str | None = Field(default=None, index=True)
|
||||
session_id: str | None = Field(default=None, index=True)
|
||||
model: str
|
||||
effort: str | None = Field(default=None)
|
||||
input_tokens: int = 0
|
||||
output_tokens: int = 0
|
||||
cache_read_tokens: int = 0
|
||||
cache_creation_tokens: int = 0
|
||||
cost_usd: float | None = Field(default=None)
|
||||
duration_ms: int | None = Field(default=None)
|
||||
num_turns: int | None = Field(default=None)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AuditLog",
|
||||
"Conversation",
|
||||
"ConversationMessage",
|
||||
"Token",
|
||||
"TranscriptEntry",
|
||||
"Usage",
|
||||
]
|
||||
Reference in new issue
Block a user