Skip to content

Conversation

@cboos
Copy link
Collaborator

@cboos cboos commented Dec 20, 2025

Summary

This PR completes a refactoring effort to simplify the message rendering architecture by:

  1. Removing Anthropic SDK type dependencies - Our models are now the canonical types
  2. Eliminating MessageModifiers - Display properties derived from content types via CSS_CLASS_REGISTRY
  3. Simplifying TemplateMessage - is_sidechain: bool replaces the entire MessageModifiers class

Key Changes

Remove Anthropic SDK Dependencies

  • Remove anthropic.types imports (Message, Usage, StopReason)
  • Remove unused conversion methods: to_anthropic_usage(), from_anthropic_usage(), from_anthropic_message()
  • Simplify normalize_usage_info() to work without SDK validation
  • Change stop_reason type from StopReason to Optional[str]

CSS_CLASS_REGISTRY Architecture

  • New registry maps content types to CSS class lists
  • css_class_from_message() walks MRO to find matching entry
  • Dynamic modifiers (system-{level}, error) derived from content attributes
  • Only is_sidechain remains as a cross-cutting flag (can't be derived from content alone)

MessageModifiers Elimination

  • Before: 7 fields (is_slash_command, is_command_output, is_compacted, is_error, is_steering, system_level, is_sidechain)
  • After: Single is_sidechain: bool on TemplateMessage
  • All other modifiers now derived via isinstance() checks on content types

New Content Type

  • UserSteeringContent for queue-operation "remove" messages (previously handled via modifier flag)

Files Changed

File Changes
models.py Remove MessageModifiers, Anthropic imports, unused methods
renderer.py Update _process_regular_message signature, use is_sidechain directly
parser.py Remove Anthropic validation, simplify usage parsing
html/utils.py Add CSS_CLASS_REGISTRY, update class derivation
html/assistant_formatters.py Fix docstring
dev-docs/messages.md Document new architecture
dev-docs/MESSAGE_REFACTORING2.md Update completed goals
dev-docs/REMOVE_ANTHROPIC_TYPES.md Document rationale

Benefits

  1. Simpler dependencies - No SDK types needed for parsing JSONL
  2. Type-driven architecture - Content type is source of truth for display
  3. Cleaner code - One bool vs. 7 modifier fields
  4. Better maintainability - CSS class logic centralized in registry

Test plan

  • All tests pass (460 passed, 1 skipped)
  • Type checking passes
  • Linting passes

Summary by CodeRabbit

  • New Features

    • Added UserSteeringContent to represent steering prompts in transcripts.
  • Bug Fixes

    • Unified markdown rendering via a has_markdown flag for more consistent display.
  • Refactor

    • Replaced modifier-driven styling with a content-type → CSS class registry.
    • Removed Anthropic SDK type dependencies and simplified message parsing/rendering paths.
  • Documentation

    • Added docs describing the message refactor and Anthropic removal plan.

✏️ Tip: You can customize this high-level summary in your review settings.

cboos and others added 7 commits December 20, 2025 15:17
- Remove anthropic.types imports (Message, Usage, StopReason)
- Remove unused methods: to_anthropic_usage(), from_anthropic_usage(),
  from_anthropic_message()
- Simplify normalize_usage_info() to handle dicts and object-like access
  without depending on Anthropic SDK validation
- Change stop_reason type from StopReason to Optional[str]
- Remove no-op AnthropicMessage.model_validate() call in parser

Our models are the canonical types for parsing JSONL transcripts - we don't
need SDK types for validation. This simplifies dependencies and ownership.

Added dev-docs documenting the rationale and future refactoring plans.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Create CSS_CLASS_REGISTRY mapping content types to CSS class lists
- Rewrite css_class_from_message() to use registry with MRO walk
- Dynamic modifiers (system-{level}, error) added based on content attributes
- Cross-cutting modifiers (steering, sidechain) still from MessageModifiers

This is a step toward eliminating redundant MessageModifiers fields
that duplicate information already present in content types.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
MessageModifiers simplified from 7 fields to just is_sidechain:
- Removed: is_slash_command, is_command_output, is_compacted, is_error, is_steering, system_level
- These are now derived from content types via CSS_CLASS_REGISTRY or content attributes

Changes:
- Create UserSteeringContent for queue-operation "remove" messages
- Set has_markdown flag based on content type (AssistantTextContent, ThinkingContentModel, CompactedSummaryContent)
- Template uses message.has_markdown instead of type checks
- Replace modifier checks with isinstance() on content types
- CSS classes now fully derived from content types (except is_sidechain)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Complete the MessageModifiers simplification by:
- Remove MessageModifiers class from models.py entirely
- Store is_sidechain as a bool directly on TemplateMessage
- Update _process_regular_message to return (is_sidechain, content, type, title)
- Update all TemplateMessage creation sites to use is_sidechain=
- Replace msg.modifiers.is_sidechain with msg.is_sidechain

All display properties are now derived from content type via
CSS_CLASS_REGISTRY, making MessageModifiers obsolete.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Document the MessageModifiers removal and new architecture:
- Add UserSteeringContent to data flow diagram and user variants
- Update TemplateMessage fields (is_sidechain, has_markdown)
- Replace MessageModifiers section with CSS_CLASS_REGISTRY docs
- Update CSS class table to show content type derivation
- Update Queue Operation section to reference UserSteeringContent

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Mark MessageModifiers removal, CSS_CLASS_REGISTRY, and
UserSteeringContent as achieved goals.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove incorrect claim about fallback behavior when items is None.
The code unconditionally iterates over content.items.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Dec 20, 2025

Walkthrough

This PR removes Anthropic SDK types, drops MessageModifiers, and refactors message rendering to a content-type-driven model with TemplateMessage flags (is_sidechain, has_markdown). It adds a CSS class registry, new UserSteeringContent, updates parsing/usage normalization, and updates templates/HTML utils to follow the new model.

Changes

Cohort / File(s) Summary
Core Model Decoupling
claude_code_log/models.py
Removed Anthropic type imports and conversion helpers; removed MessageModifiers; added UserSteeringContent (subclass of UserTextContent); changed AssistantMessage.stop_reason to Optional[str].
Parser Simplification
claude_code_log/parser.py
Removed Anthropic-specific message/usage branches; unified normalize_usage_info to accept object-like usage and dicts; parse_transcript_entry uses standard content parsing and centralized usage normalization.
Renderer Architecture Refactor
claude_code_log/renderer.py
Removed modifiers usage; added is_sidechain and has_markdown on TemplateMessage; refactored _process_* and _process_regular_message signatures to drop modifiers and return content/type/title (and is_sidechain); replaced modifier checks with content-type checks and updated call sites.
HTML Utilities & Styling
claude_code_log/html/utils.py
Introduced CSS_CLASS_REGISTRY and _get_css_classes_from_content; refactored css_class_from_message to derive classes from content types and message flags; updated emoji logic to rely on content-type/flags; expanded content-type imports.
Templates & Formatters
claude_code_log/html/templates/transcript.html,
claude_code_log/html/assistant_formatters.py
transcript.html now uses message.has_markdown to control markdown rendering; format_assistant_text_content docstring simplified (no behavioral code changes).
Docs & Guides
dev-docs/MESSAGE_REFACTORING2.md,
dev-docs/REMOVE_ANTHROPIC_TYPES.md,
dev-docs/messages.md
Added refactor/design docs: message refactor phase 2, Anthropic removal plan, updated messages.md describing UserSteeringContent, CSS_CLASS_REGISTRY, and TemplateMessage field changes.
Build
pyproject.toml
Removed anthropic>=0.72.0 dependency from project dependencies.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Parser
participant Renderer
participant HTMLUtils as "HTML utils / CSS registry"
participant Template as "transcript template"
Parser->>Renderer: parse_transcript_entry -> MessageContent + usage
Renderer->>HTMLUtils: request CSS classes / emoji (content-type)
HTMLUtils-->>Renderer: CSS class list, dynamic modifiers
Renderer->>Template: render TemplateMessage (is_sidechain, has_markdown, content, title)
Template-->>Client: final HTML chunk

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • claude_code_log/renderer.py — many signature and contract changes; verify all call sites and public exports.
    • claude_code_log/html/utils.py — CSS registry and dynamic modifier logic correctness and coverage for content types.
    • claude_code_log/parser.py — usage normalization and removal of Anthropic branches (edge-case handling for existing usage objects).

Possibly related PRs

Suggested reviewers

  • daaain

Poem

🐰 Hopping through code with a twitch of delight,

I traded old modifiers for types shining bright,
CSS maps now lead each message's attire,
Anthropic chains gone — we bounce, build, and inspire! ✨

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 'Remove MessageModifiers' directly and accurately reflects the main change in the PR—the elimination of the MessageModifiers class and its replacement with simpler, content-type-driven mechanisms throughout the codebase.
Docstring Coverage ✅ Passed Docstring coverage is 94.74% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev/remove-MessageModifiers

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 179c230 and 6bfbb90.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • pyproject.toml (0 hunks)
💤 Files with no reviewable changes (1)
  • pyproject.toml
⏰ 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). (10)
  • GitHub Check: test (windows-latest, 3.11)
  • GitHub Check: test (windows-latest, 3.12)
  • GitHub Check: test (ubuntu-latest, 3.14)
  • GitHub Check: test (ubuntu-latest, 3.11)
  • GitHub Check: test (windows-latest, 3.14)
  • GitHub Check: test (ubuntu-latest, 3.13)
  • GitHub Check: test (ubuntu-latest, 3.10)
  • GitHub Check: test (windows-latest, 3.13)
  • GitHub Check: test (windows-latest, 3.10)
  • GitHub Check: test (ubuntu-latest, 3.12)

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

@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

🧹 Nitpick comments (3)
dev-docs/REMOVE_ANTHROPIC_TYPES.md (2)

15-19: Consider removing or updating line number references.

The line number references (e.g., models.py:711, models.py:725, models.py:808) will become stale as the code evolves. Consider either:

  • Removing the specific line numbers
  • Using stable anchors like method names only

This is a minor documentation maintenance concern.


39-52: Incomplete code example in Phase 2.

The code example ends with an ellipsis (...) on line 50, which makes it unclear what additional fields should be included. Consider completing the example or adding a comment indicating it's a partial snippet:

-        ...
+        cache_creation_input_tokens=getattr(usage_data, "cache_creation_input_tokens", None),
+        cache_read_input_tokens=getattr(usage_data, "cache_read_input_tokens", None),
+        output_tokens=getattr(usage_data, "output_tokens", None),
+        service_tier=getattr(usage_data, "service_tier", None),
+        server_tool_use=getattr(usage_data, "server_tool_use", None),
     )
dev-docs/MESSAGE_REFACTORING2.md (1)

8-8: Clarify vision vs. current state for has_markdown.

Line 8 lists has_markdown as a "derived/redundant field" to remove under the "Leaner models" vision. However, this PR introduces has_markdown as a new flag on TemplateMessage (used in transcript.html line 105).

This appears to be an aspirational goal rather than something being removed now. Consider clarifying this is a future goal:

-3. **Leaner models** - Remove derived/redundant fields like `has_children`, `has_markdown`, `is_session_header`, `raw_text_content`
+3. **Leaner models** - Eventually remove derived/redundant fields like `has_children`, `has_markdown`, `is_session_header`, `raw_text_content` once content types fully encapsulate this information
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 731b551 and 179c230.

📒 Files selected for processing (9)
  • claude_code_log/html/assistant_formatters.py (1 hunks)
  • claude_code_log/html/templates/transcript.html (1 hunks)
  • claude_code_log/html/utils.py (2 hunks)
  • claude_code_log/models.py (4 hunks)
  • claude_code_log/parser.py (2 hunks)
  • claude_code_log/renderer.py (18 hunks)
  • dev-docs/MESSAGE_REFACTORING2.md (1 hunks)
  • dev-docs/REMOVE_ANTHROPIC_TYPES.md (1 hunks)
  • dev-docs/messages.md (7 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use ruff for code formatting and linting, with ruff check --fix for automatic fixes
Use pyright and mypy for type checking in Python code
Target Python 3.10+ with support for modern Python features and type hints

Files:

  • claude_code_log/html/assistant_formatters.py
  • claude_code_log/parser.py
  • claude_code_log/html/utils.py
  • claude_code_log/models.py
  • claude_code_log/renderer.py
claude_code_log/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use dateparser for natural language date parsing to support date range filtering with expressions like 'today', 'yesterday', 'last week', and relative dates

Files:

  • claude_code_log/parser.py
  • claude_code_log/models.py
  • claude_code_log/renderer.py
claude_code_log/models.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic models for parsing and validating transcript JSON data, including TranscriptEntry (union of UserTranscriptEntry, AssistantTranscriptEntry, SummaryTranscriptEntry), UsageInfo, and ContentItem

Files:

  • claude_code_log/models.py
claude_code_log/renderer.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use mistune for quick Markdown rendering with syntax highlighting support in server-side template rendering

Files:

  • claude_code_log/renderer.py
🧠 Learnings (5)
📚 Learning: 2025-11-30T17:16:32.495Z
Learnt from: CR
Repo: daaain/claude-code-log PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T17:16:32.495Z
Learning: Applies to claude_code_log/templates/**/*.html : Use Jinja2 templates for HTML generation, including session navigation with table of contents, message rendering with different content types, and token display for individual messages and session totals

Applied to files:

  • claude_code_log/html/templates/transcript.html
📚 Learning: 2025-11-30T17:16:32.495Z
Learnt from: CR
Repo: daaain/claude-code-log PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T17:16:32.495Z
Learning: Applies to claude_code_log/renderer.py : Use mistune for quick Markdown rendering with syntax highlighting support in server-side template rendering

Applied to files:

  • claude_code_log/html/templates/transcript.html
📚 Learning: 2025-11-30T17:16:32.495Z
Learnt from: CR
Repo: daaain/claude-code-log PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T17:16:32.495Z
Learning: Applies to claude_code_log/models.py : Use Pydantic models for parsing and validating transcript JSON data, including TranscriptEntry (union of UserTranscriptEntry, AssistantTranscriptEntry, SummaryTranscriptEntry), UsageInfo, and ContentItem

Applied to files:

  • claude_code_log/parser.py
  • claude_code_log/models.py
  • claude_code_log/renderer.py
📚 Learning: 2025-11-30T17:16:32.494Z
Learnt from: CR
Repo: daaain/claude-code-log PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T17:16:32.494Z
Learning: When adding new message types or modifying CSS class generation in renderer.py, ensure the timeline's message type detection logic in the JavaScript timeline component (timeline.html) is updated accordingly to maintain feature parity

Applied to files:

  • dev-docs/messages.md
  • claude_code_log/html/utils.py
  • claude_code_log/renderer.py
📚 Learning: 2025-11-30T23:24:07.840Z
Learnt from: cboos
Repo: daaain/claude-code-log PR: 54
File: claude_code_log/renderer.py:2912-2945
Timestamp: 2025-11-30T23:24:07.840Z
Learning: In claude_code_log/renderer.py, the agentId field is currently only set on Task tool_result messages, not on tool_use messages, because the agentId is generated after the tool_use is logged. The _reorder_sidechain_template_messages function relies on this to avoid duplicate sidechain insertion.

Applied to files:

  • claude_code_log/renderer.py
🧬 Code graph analysis (2)
claude_code_log/parser.py (1)
claude_code_log/models.py (1)
  • UsageInfo (684-692)
claude_code_log/html/utils.py (2)
claude_code_log/models.py (17)
  • AssistantTextContent (317-333)
  • BashInputContent (132-138)
  • BashOutputContent (142-149)
  • CommandOutputContent (121-128)
  • CompactedSummaryContent (168-177)
  • MessageContent (56-66)
  • SessionHeaderContent (491-500)
  • SlashCommandContent (108-117)
  • SystemContent (70-77)
  • ThinkingContentModel (337-348)
  • ToolResultContentModel (153-164)
  • ToolUseContent (695-718)
  • UnknownContent (352-359)
  • UserMemoryContent (181-189)
  • UserSlashCommandContent (193-201)
  • UserSteeringContent (299-306)
  • UserTextContent (281-295)
claude_code_log/renderer.py (1)
  • TemplateMessage (169-265)
⏰ 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). (10)
  • GitHub Check: test (ubuntu-latest, 3.12)
  • GitHub Check: test (windows-latest, 3.11)
  • GitHub Check: test (ubuntu-latest, 3.13)
  • GitHub Check: test (ubuntu-latest, 3.10)
  • GitHub Check: test (ubuntu-latest, 3.14)
  • GitHub Check: test (windows-latest, 3.14)
  • GitHub Check: test (windows-latest, 3.12)
  • GitHub Check: test (ubuntu-latest, 3.11)
  • GitHub Check: test (windows-latest, 3.10)
  • GitHub Check: test (windows-latest, 3.13)
🔇 Additional comments (21)
claude_code_log/models.py (2)

298-306: LGTM - New content type for steering prompts.

The UserSteeringContent subclass appropriately inherits from UserTextContent to represent queue-operation "remove" messages. Using inheritance for type differentiation enables the CSS class registry to map this content type to appropriate styling classes. As per the coding guidelines, this follows the Pydantic/dataclass pattern used throughout the models.


684-685: LGTM - Anthropic SDK type dependencies removed.

The changes align with the PR objective:

  • UsageInfo docstring simplified (removed Anthropic conversion references)
  • AssistantMessage.stop_reason changed from Optional[StopReason] to Optional[str], decoupling from Anthropic SDK types

This simplification is appropriate since the stop reason is just a string value from the JSONL data.

Also applies to: 751-752, 759-759

claude_code_log/html/assistant_formatters.py (1)

34-36: LGTM - Docstring simplified to match implementation.

The updated docstring accurately reflects the current implementation which directly iterates over content.items. The removal of the "When items is set" phrasing aligns with the broader refactoring that removes fallback behaviors and relies on content-type-driven rendering.

claude_code_log/html/templates/transcript.html (1)

105-105: LGTM - Simplified markdown detection using explicit flag.

The change from type-based conditional logic to using message.has_markdown is a clean improvement. This moves the markdown determination logic from the template to Python code (in the renderer), making it:

  • Easier to test
  • More maintainable
  • Consistent with the content-type-driven architecture

This aligns with the learning that Jinja2 templates should focus on rendering rather than complex logic.

dev-docs/MESSAGE_REFACTORING2.md (1)

1-63: Good architectural documentation.

This document effectively captures:

  • The vision for type-driven architecture
  • Current state and achievements (CSS_CLASS_REGISTRY, MessageModifiers removal, UserSteeringContent)
  • Cache layer implications (important for backwards compatibility)
  • Future modular organization plan

The reference to REMOVE_ANTHROPIC_TYPES.md ties the documentation together well.

claude_code_log/html/utils.py (4)

56-79: Well-structured CSS class registry.

The registry-based approach is a clean improvement over the previous modifier system. The organization by message category (system, user, assistant, tool, other) aids maintainability.

One consideration: UserMemoryContent maps to ["user"] only, while other specialized user types get additional classes. If memory messages need distinct styling in the future, this would need updating.


82-99: MRO-based lookup is correct.

The MRO walk correctly handles inheritance (e.g., UserSteeringContent extending UserTextContent). The early continue for non-MessageContent classes is a good guard.

Minor observation: The function returns an empty list if no registry match is found, which is handled by the fallback in css_class_from_message. This is correct.


152-168: Content-type checks in emoji logic are appropriate.

The emoji logic correctly uses isinstance checks for CommandOutputContent and ToolResultContentModel to determine emojis. This aligns with the content-type-driven approach.


105-134: CSS class generation is compatible with timeline message type detection.

The timeline.html detection logic correctly handles all CSS classes generated by css_class_from_message(). Primary message types (user, assistant, tool_use, etc.) and system variants (system-warning, system-error, system-info) are properly detected. Modifier classes like steering, compacted, and error are used for styling and don't affect timeline grouping. The fallback mechanism ensures unknown content types default gracefully.

claude_code_log/parser.py (2)

712-743: Flexible usage normalization handles multiple input formats.

The updated normalize_usage_info correctly handles:

  1. UsageInfo instances (passthrough)
  2. Dict input (via model_validate)
  3. Object-like access (e.g., SDK types with attributes)

The server_tool_use handling correctly checks for model_dump method before calling it, which handles both Pydantic models and plain dicts.


916-932: Assistant message parsing simplified.

The assistant parsing now uses a unified path with parse_message_content and normalizes usage data consistently. The removal of Anthropic-specific type checks aligns with the PR objective.

dev-docs/messages.md (2)

96-121: Documentation accurately reflects the CSS class registry.

The table correctly documents the content-type to CSS class mappings, including dynamic modifiers. The note about sidechain being a cross-cutting modifier applied via msg.is_sidechain is helpful.


250-265: UserSteeringContent documentation is clear and accurate.

The documentation correctly describes UserSteeringContent as extending UserTextContent and explains its purpose for queue-operation "remove" messages. The CSS class and title are consistent with the implementation in renderer.py.

claude_code_log/renderer.py (8)

191-198: TemplateMessage correctly uses is_sidechain flag.

The is_sidechain parameter and attribute replace the previous modifier-based approach. The initialization is clean and the attribute is used consistently throughout the rendering pipeline.


643-693: Processing functions return simplified tuples without modifiers.

The _process_* functions now return (content, message_type, message_title) tuples, removing the modifier baggage. _process_regular_message additionally returns is_sidechain as the first element, which is appropriate since sidechain status can be modified during processing.


1073-1076: Content-type checks for pairing indices.

The pairing index correctly identifies slash-command messages using isinstance checks on content types (SlashCommandContent, UserSlashCommandContent). This is consistent with the new content-type-driven approach.


1108-1112: Adjacent pairing uses content-type checks.

The slash command + command output pairing correctly uses isinstance checks for both message types. This is cleaner than the previous modifier-based approach.


1328-1342: Hierarchy level derives system level from content.

The hierarchy level calculation correctly extracts the level attribute from SystemContent to determine if it's info/warning (level 3) vs other system messages (level 2). The isinstance check ensures type safety.


2116-2123: UserSteeringContent conversion for queue-operation 'remove'.

The conversion from UserTextContent to UserSteeringContent for queue-operation "remove" messages is correct. The isinstance check ensures the conversion only happens when appropriate.


2138-2164: has_markdown flag correctly determined from content types.

The has_markdown flag is computed based on content types that should be rendered as markdown (AssistantTextContent, ThinkingContentModel, CompactedSummaryContent). This is passed to TemplateMessage and will be used by the template for rendering decisions.


2216-2237: Tool message has_markdown correctly set for thinking content.

The thinking content correctly gets has_markdown=True while other tool types get False. This ensures proper markdown rendering for thinking blocks.

@daaain
Copy link
Owner

daaain commented Dec 20, 2025

Let's completely remove the dep to make sure the migration is clean?

@cboos
Copy link
Collaborator Author

cboos commented Dec 20, 2025

Let's completely remove the dep to make sure the migration is clean?

Well, that I didn't dare to do until now, still fearing I was missing something ;-)

The anthropic package was only used for types which have been replaced
with local Pydantic models. No code imports anthropic anymore.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@cboos cboos merged commit 693db5a into main Dec 20, 2025
11 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.

3 participants