Transcript API Reference¶
Rich transcript modeling for context engineering.
Transcript¶
Main class for loading and manipulating transcripts.
Constructor¶
Transcript(
path: str | Path | None = None,
auto_load: bool = True,
validate: Literal["strict", "warn", "none"] = "warn",
include_archived: bool = False,
include_meta: bool = False,
)
| Parameter | Description |
|---|---|
path |
Path to transcript JSONL file |
auto_load |
Load file immediately (default True) |
validate |
Unknown block handling: strict=error, warn=warning, none=silent |
include_archived |
Include pre-compaction entries in views |
include_meta |
Include system meta entries in views |
Properties¶
| Property | Type | Description |
|---|---|---|
entries |
list[TranscriptEntry] |
Current context window entries |
archived |
list[TranscriptEntry] |
Pre-compaction entries |
all_entries |
list[TranscriptEntry] |
archived + entries |
user_messages |
list[UserMessage] |
User message entries |
assistant_messages |
list[AssistantMessage] |
Assistant message entries |
tool_uses |
list[ToolUseBlock] |
All tool use blocks |
tool_results |
list[ToolResultBlock] |
All tool result blocks |
errors |
list[ToolResultBlock] |
Tool results with is_error=True |
turns |
list[Turn] |
Entries grouped by requestId |
compact_boundaries |
list[CompactBoundary] |
Compaction markers |
stats |
TranscriptStats |
Aggregated statistics |
CRUD Methods¶
# Insert (graph operations take a MessageEntry — the entry must carry a uuid)
transcript.insert(index: int, entry: MessageEntry) -> None
transcript.append(entry: MessageEntry) -> None
# Remove
transcript.remove(entry: MessageEntry, relink: bool = True) -> None
transcript.remove_tree(entry: MessageEntry) -> list[MessageEntry]
# Replace
transcript.replace(old: MessageEntry, new: MessageEntry) -> None
# Persistence
transcript.load() -> None
transcript.save() -> None
# Batch operations
with transcript.batch():
# Auto-commit on success, rollback on exception
...
Lookup Methods¶
transcript.find_by_uuid(uuid: str) -> MessageEntry | None
transcript.find_tool_use(tool_use_id: str) -> ToolUseBlock | None
transcript.find_tool_result(tool_use_id: str) -> ToolResultBlock | None
transcript.find_snapshot(message_id: str) -> FileHistorySnapshot | None
transcript.get_parent(entry: MessageEntry) -> MessageEntry | None
transcript.get_children(entry: MessageEntry) -> list[MessageEntry]
transcript.get_logical_parent(entry: MessageEntry) -> MessageEntry | None
Export Methods¶
# To string
transcript.to_markdown(**kwargs) -> str
transcript.to_html(**kwargs) -> str
transcript.to_json(indent: int = 2) -> str
transcript.to_jsonl() -> str
# To file
transcript.to_file(
path: str | Path,
format: Literal["md", "html", "json", "jsonl"] = "md",
**kwargs
) -> None
Entry Types¶
Entry (Base)¶
Entry is the base for any JSONL stream record — messages and bookkeeping
alike. It holds only what every record shares; the conversation-graph fields live
on MessageEntry so non-message records (e.g. FileHistorySnapshot) don't
inherit them.
MessageEntry¶
A record that participates in the conversation graph (carries uuid/parent_uuid
and session metadata). UserMessage, AssistantMessage, and SystemEntry extend
it. isinstance(e, MessageEntry) means "has graph identity" — the discriminator
that separates messages from FileHistorySnapshot.
class MessageEntry(Entry):
uuid: str
parent_uuid: str | None
timestamp: datetime | None
session_id: str
cwd: str
version: str
git_branch: str
is_sidechain: bool
is_synthetic: bool
UserMessage¶
class UserMessage(MessageEntry):
type: Literal["user"] = "user"
# Properties
content: str | list[ToolResultBlock]
text: str # Empty if tool result
is_tool_result: bool
tool_results: list[ToolResultBlock]
# Factory
@classmethod
def create(
cls,
content: str,
*,
parent: MessageEntry | None = None,
context: MessageEntry | None = None,
**overrides
) -> UserMessage
AssistantMessage¶
class AssistantMessage(MessageEntry):
type: Literal["assistant"] = "assistant"
request_id: str
# Properties
message_id: str
model: str
content: list[ContentBlock]
stop_reason: str | None
usage: dict
text: str
thinking: str
tool_uses: list[ToolUseBlock]
has_tool_use: bool
# Factory
@classmethod
def create(
cls,
content: str | list[ContentBlock],
*,
parent: MessageEntry | None = None,
context: MessageEntry | None = None,
model: str = "synthetic",
stop_reason: str = "end_turn",
**overrides
) -> AssistantMessage
SystemEntry¶
class SystemEntry(MessageEntry):
type: Literal["system"] = "system"
subtype: str
content: str
level: str
CompactBoundary¶
class CompactBoundary(SystemEntry):
subtype: Literal["compact_boundary"] = "compact_boundary"
logical_parent_uuid: str
compact_metadata: dict
Content Blocks¶
TextBlock¶
ToolUseBlock¶
class ToolUseBlock:
type: Literal["tool_use"] = "tool_use"
id: str
name: str
input: dict
# Property - finds matching result
result: ToolResultBlock | None
ToolResultBlock¶
class ToolResultBlock:
type: Literal["tool_result"] = "tool_result"
tool_use_id: str
content: str
is_error: bool
# Property - finds matching tool use
tool_use: ToolUseBlock | None
ThinkingBlock¶
class ThinkingBlock:
type: Literal["thinking"] = "thinking"
thinking: str
signature: str # Cryptographic signature (read-only)
Turn¶
Groups assistant entries by requestId.
class Turn:
request_id: str
entries: list[AssistantMessage]
# Properties
thinking: str
text: str
tool_uses: list[ToolUseBlock]
is_complete: bool
has_error: bool
TranscriptStats¶
class TranscriptStats:
input_tokens: int
output_tokens: int
cache_read_tokens: int
cache_creation_tokens: int
tool_calls: dict[str, int]
error_count: int
message_count: int
turn_count: int
compact_count: int
duration_seconds: float
slug: str
Factory Functions¶
inject_tool_result¶
from fasthooks.transcript import inject_tool_result
inject_tool_result(
transcript: Transcript,
tool_name: str,
tool_input: dict,
result: str,
*,
is_error: bool = False,
position: int | Literal["start", "end"] = "end",
) -> tuple[AssistantMessage, UserMessage]
Creates a matching ToolUseBlock + ToolResultBlock pair and inserts them.