Skip to content

Conversation

@Boredphilosopher96
Copy link
Contributor

AI-Powered Session Title Generation

Summary

This PR implements intelligent, AI-powered session title generation to improve session discoverability and organization. Instead of relying on timestamps alone, Code Puppy now automatically generates descriptive titles based on the user's first prompt, making it dramatically easier to identify and restore previous sessions.

Problem Statement

Previously, autosaved sessions were identified only by timestamps (e.g., auto_session_20240101_010101), making it difficult for users to:

  • Quickly identify what a session was about
  • Find specific past conversations
  • Understand session context at a glance

Solution

Implemented a lightweight, non-blocking AI title generation system that:

Generates concise titles (≤10 words) based on the user's first meaningful prompt
Falls back gracefully to truncated prompts if AI generation fails
Caches titles to avoid redundant generation
Preserves titles when re-saving existing sessions
Runs asynchronously in a background thread pool to avoid blocking the UI
Maintains backwards compatibility with existing sessions (no breaking changes)

Changes Made

Core Implementation

  • Added session_title field to SessionMetadata model with optional typing for backwards compatibility
  • Implemented maybe_generate_session_title() function that:
    • Uses a dedicated PydanticAgent with custom instructions
    • Sanitizes and truncates input prompts (max 500 chars)
    • Enforces 10-word maximum on generated titles
    • Caches titles in-memory to prevent duplicate generation
    • Falls back to first 10 words of user prompt if AI generation fails

Integration Points

CLI Interactive Mode (code_puppy/main.py)

  • Integrated title generation after first successful agent response
  • Only triggers on non-command prompts (filters out / commands)
  • Gracefully handles errors without breaking user experience

TUI Mode (code_puppy/tui/app.py)

  • Mirrors CLI behavior in the textual user interface
  • Displays warnings in chat if title generation fails
  • Maintains consistent UX across both modes

Session Display (code_puppy/session_storage.py)

  • Updated restore_autosave_interactively() to display titles in session listings
  • Format: session_name — title — message_count, saved at timestamp
  • Gracefully handles missing titles (backwards compatible)

TUI Session Picker (code_puppy/tui/screens/autosave_picker.py)

  • Enhanced AutosaveEntry dataclass with optional session_title field
  • Updated _load_metadata() to extract title from metadata JSON
  • Updated list item rendering to include titles when available

Session Storage

  • Modified save_session() to:
    • Accept optional session_title parameter
    • Retrieve existing titles from metadata if not provided
    • Persist titles to metadata JSON
    • Return title in SessionMetadata object

Configuration Helpers

  • Added private module-level caches:

    • _SESSION_FIRST_PROMPT: Tracks first prompt per session
    • _SESSION_TITLE_CACHE: Caches generated titles per session
    • _TITLE_AGENT: Singleton PydanticAgent for title generation
    • _TITLE_THREAD_POOL: ThreadPoolExecutor for async title generation
  • Added helper functions:

    • _ensure_title_agent(): Lazy initialization of title generation agent
    • _ensure_title_thread_pool(): Thread pool management
    • _generate_session_title_async(): Async AI title generation
    • _generate_session_title(): Sync wrapper with event loop handling

Technical Details

Design Patterns & Principles

  • Lazy Initialization: Title agent and thread pool are only created when needed
  • Caching Strategy: Two-level cache (first prompt + generated title) prevents redundant work
  • Graceful Degradation: Multiple fallback layers ensure feature never breaks core functionality
  • Separation of Concerns: Title generation logic isolated in config.py, not scattered across codebase
  • Single Responsibility: Each function has one clear purpose
  • Backwards Compatibility: All changes are additive; old sessions load without titles

Thread Safety & Async Handling

  • Uses ThreadPoolExecutor to avoid blocking the main event loop
  • Properly handles both running and non-running event loops
  • Defensive timeout handling (agent configured with retries=1)

AI Agent Configuration

Instructions: "You generate concise session titles based on a user's first prompt. 
               Respond with fewer than ten words, title case preferred, and avoid 
               punctuation beyond spaces."

Constraints:
- Max input: 500 characters (sanitized from user prompt)
- Max output: 10 words (enforced defensively)
- Model: Uses global model configuration
- Retries: 1 (fast-fail for non-critical feature)

Metadata Schema Extension

Before:

{
  "session_name": "auto_session_20240101_010101",
  "message_count": 5,
  "total_tokens": 1234,
  "timestamp": "2024-01-01T00:00:00",
  "auto_saved": true
}

After:

{
  "session_name": "auto_session_20240101_010101",
  "message_count": 5,
  "total_tokens": 1234,
  "timestamp": "2024-01-01T00:00:00",
  "auto_saved": true,
  "session_title": "Implement Session Title Generation"  // NEW
}

Files Modified

File Changes Lines
code_puppy/config.py Added title generation logic, caching, and helper functions +120
code_puppy/main.py Integrated title generation in CLI interactive loop +15
code_puppy/session_storage.py Enhanced to store/retrieve/display session titles +35
code_puppy/tui/app.py Integrated title generation in TUI message handling +22
code_puppy/tui/screens/autosave_picker.py Updated picker to display titles in session list +12
tests/test_session_storage.py Added tests for title persistence and retrieval +35
tests/test_auto_save_session.py Updated test assertions for new metadata field +2

Key File Changes

code_puppy/config.py

  • 📦 Added _SESSION_TITLE_CACHE, _SESSION_FIRST_PROMPT, _TITLE_AGENT, _TITLE_THREAD_POOL module globals
  • 🎯 Implemented maybe_generate_session_title() - main public API
  • 🔧 Added _ensure_title_agent(), _ensure_title_thread_pool() for resource management
  • ⚡ Added _generate_session_title_async(), _generate_session_title() for AI generation
  • 🔄 Modified auto_save_session_if_enabled() to include cached titles

code_puppy/session_storage.py

  • 📝 Modified save_session() to accept and persist session_title
  • 🔍 Added logic to retrieve existing titles from metadata when not provided
  • 🖥️ Updated restore_autosave_interactively() to display titles in listings
  • 📊 Modified tuple unpacking throughout to handle 4-element tuples (name, ts, count, title)

code_puppy/main.py & code_puppy/tui/app.py

  • 🎬 Added post-response hook to trigger title generation
  • 🚫 Filters out meta-commands (starting with /)
  • ⚠️ Error handling with user-visible warnings in TUI mode

code_puppy/tui/screens/autosave_picker.py

  • 🏷️ Extended AutosaveEntry dataclass with session_title field
  • 🔄 Updated _load_metadata() to return 3-tuple (timestamp, count, title)
  • 🎨 Enhanced list item labels to show name — title — metadata

Testing

New Test Coverage

tests/test_session_storage.py::test_save_session_with_title

  • ✅ Verifies title is saved to metadata JSON
  • ✅ Confirms title is returned in SessionMetadata object
  • ✅ Tests title persistence across multiple saves
  • ✅ Validates title retrieval when not explicitly provided

tests/test_auto_save_session.py

  • ✅ Updated assertions to expect session_title=None in metadata
  • ✅ Ensures backwards compatibility with existing tests

Manual Testing Performed

  • ✅ Verified title generation in CLI interactive mode
  • ✅ Verified title generation in TUI mode
  • ✅ Confirmed graceful fallback when AI generation fails
  • ✅ Tested session listing displays with and without titles
  • ✅ Validated backwards compatibility with old session files
  • ✅ Confirmed title caching prevents redundant generation

Breaking Changes

None. This feature is fully backwards compatible:

  • Old sessions without titles continue to work
  • session_title field is optional in all contexts
  • Title display gracefully handles None values
  • No changes to existing session file formats (only additions)

Additional Notes

Performance Considerations

  • Title generation runs in background thread pool - zero blocking
  • Caching prevents redundant AI calls for the same session
  • Fast-fail strategy (1 retry) ensures minimal latency impact
  • Fallback to prompt truncation is instantaneous

Future Enhancements

  • Add user preference to disable title generation
  • Allow manual title editing
  • Support regenerating titles for existing sessions
  • Add title search/filter in session picker

Code Quality

✅ Follows DRY principles - title logic centralized in config.py
✅ Follows SRP - each function has single, clear responsibility
✅ Follows YAGNI - no speculative features, only what's needed
✅ Type hints on all new functions
✅ Comprehensive docstrings
✅ No files exceed 600 lines


Checklist

  • Code follows project style guidelines
  • Added tests for new functionality
  • All tests pass
  • No breaking changes
  • Documentation updated (inline docstrings)
  • Backwards compatible with existing sessions
  • Performance impact minimized (async execution)
  • Error handling implemented
  • Type hints added

Related Issues

Improves user experience for session management and autosave functionality.

Copy link
Owner

@mpfaffenberger mpfaffenberger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I think some different structure may be needed, but I like it!

_TITLE_AGENT = None
_TITLE_THREAD_POOL: Optional[ThreadPoolExecutor] = None

_TITLE_AGENT_INSTRUCTIONS = (
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this live in side agents/?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, having it inside code_puppy folder makes more sense. This is similar to summarization agent than it is to anything inside agents folder. But have moved it out of config per your suggestion

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking I need to move that summarizer into the agents namespace

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mpfaffenberger have now moved it to code_puppy folder. Please let me know if it is ok now

github-actions bot and others added 29 commits October 25, 2025 12:59
Introduce a new plugin system that allows users to create custom slash commands by placing markdown files in specific directories. This feature enables users to define reusable prompts and commands without modifying the core codebase.

- Add customizable_commands plugin with automatic discovery and registration
- Support command files in .claude/commands/, .github/prompts/, and .agents/commands/ directories
- Implement MarkdownCommandResult class for seamless integration with existing command handler
- Update command handler to process markdown command results as input
- Add comprehensive documentation with usage examples in README
- Include message limit configuration for agent tool invocations
…broad exception handlers

The autosave calls were being swallowed by overly broad try/except blocks
in both main.py (interactive mode) and tui/app.py (TUI mode), causing
autosaves to fail silently without user notification.

- Move auto_save_session_if_enabled() call outside the broad exception handler in main.py
- Remove silent exception swallowing in TUI mode autosave call
- Ensures autosave errors are properly visible to users
- Fixes regression caused by race condition fix that introduced overly broad exception handling
- Add new auto_save_session config option with default value "true"
- Display auto_save_session status in command handler output
- Ensure auto_save_session is set when creating/updating config files
- Show current value as enabled/disabled in status information
* adding planning agent

* format
Integrate Claude Code OAuth authentication into Code Puppy, enabling users to authenticate through browser and automatically import available models.

- Implement complete OAuth 2.0 flow with PKCE security for Claude Code
- Add three custom commands: auth, status, and logout for token management
- Automatically fetch and register Claude Code models with 'claude-code-' prefix
- Securely store OAuth tokens in ~/.code_puppy with proper file permissions
- Include comprehensive test suite and detailed setup documentation
- Improve version handling fallback for development environments
…entication

- Add comprehensive ChatGPT OAuth plugin with browser-based authentication flow
- Implement PKCE OAuth flow matching OpenAI's official Codex CLI implementation
- Automatically fetch and register available ChatGPT models with 'chatgpt-' prefix
- Provide custom commands: /chatgpt-auth, /chatgpt-status, /chatgpt-logout
- Store tokens securely in ~/.code_puppy/chatgpt_oauth.json with 0600 permissions
- Exchange OAuth tokens for OpenAI API keys when organization/project is configured
- Refactor existing Claude Code OAuth plugin to use dedicated model files for better separation
- Update model factory to load from multiple model configuration sources
- Include comprehensive documentation, setup guides, and test coverage
- Add task tracking to enable graceful shutdown of running agent operations
- Modify run_prompt_with_attachments to return both result and asyncio task
- Update interactive mode to cancel running tasks on /exit and /quit commands
- Refactor ChatGPT OAuth plugin to create fresh OAuth contexts per instance
- Remove global OAuth context state machine for better isolation
- Update OAuth client ID configuration for Code Puppy application
- Delete unused math_utils.py file
- Removed complex API key exchange flow in favor of direct OAuth token usage like ChatMock
- Fixed JWT parsing to handle nested organization structure from user's payload
- Consolidated OAuth success/failure HTML templates into shared oauth_puppy_html module
- Replaced urllib.request/ssl with requests library for consistent HTTP handling
- Simplified token storage and model fetching logic
- Removed extensive documentation files (SETUP.md, README.md, ENABLE.md)
- Updated ChatGPT and Claude OAuth plugins to use shared HTML templates
- Fixed codex model to use OpenAIResponsesModel instead of OpenAIChatModel
- Filtered empty thinking parts from message history processing
- Added comprehensive test cases for JWT parsing with nested organization structure
…ents

- Assign underscore to second return value in test_run_prompt_with_attachments_passes_binary
- Assign underscore to second return value in test_run_prompt_with_attachments_warns_on_blank_prompt
- Maintains test compatibility with updated function signature that now returns a tuple
- Introduce new claude_code model type in ModelFactory with custom OAuth authentication
- Add specialized system prompt handling for Claude Code models in BaseAgent
- Update Claude Code OAuth plugin to use claude_code model type with proper headers
- Temporarily disable ChatGPT OAuth callbacks due to current implementation issues
- Include OAuth-specific headers (anthropic-beta) for Claude Code API compatibility
- Update model retrieval to use agent-specific configuration instead of global model
- Add special handling for Claude Code models with custom instructions
- Prepend Claude Code system prompt when applicable to ensure proper behavior
- Maintain separation between agent-specific and general prompt instructions
Fresh models on every auth! 🎾

- Changed add_models_to_extra_config() to start with empty dict
- Removes stale/accumulated models from previous auth sessions
- Ensures ~/.code_puppy/claude_models.json always reflects current API state
- Cleaner approach: overwrite instead of load-merge-save pattern

Now every /claude-code-auth gives you a clean slate with only the
models currently available from Claude Code's API. No more cruft!
* adding planning agent

* format

* improve prompt

* improve prompt for safegurading

* add plugin for callback

* yolo

* planning agent

* format
- Add mock for get_yolo_mode to ensure consistent test behavior
- Update assertion to match current prompt text format
- Prevent test failures due to environment-dependent yolo mode settings
- Added new custom OpenAI-compatible model configuration for MiniMax-M2
- Configured to use synthetic API endpoint with environment variable authentication
- Set context length to 205,000 tokens for extended conversation support
mpfaffenberger and others added 10 commits December 11, 2025 19:30
- Changed logo display condition from checking interactive mode to checking for non-prompt mode
- This ensures the logo appears for both `code-puppy` and `code-puppy -i` commands
- Print logo directly to console instead of using emit_system_message to avoid dim styling
- Added comment clarification about when the logo should be displayed
- Removed unnecessary blank line before logo for better visual presentation
…patches

- Add dynamic User-Agent patch to use "KimiCLI/0.63" for Kimi models and "Code-Puppy/{version}" for others
- Refactor pydantic-ai monkey patches into dedicated module for better organization and reusability
- Extend API key resolution to check config before environment variables using new get_api_key() helper
- Fix kimi-for-coding model name to use "kimi-for-coding" instead of model_id from models.dev
- Add Rich markup escaping throughout renderers to prevent crashes from malformed tags in user content
- Suppress shell command output rendering to avoid UI clutter since results are sent via tool responses
- Improve diff rendering by preserving exact formatting for diff headers and syntax highlighting
- Update warning messages to indicate API keys are checked in both config and environment
- Updated test assertions to match new warning message format
- Messages now include "(check config or environment)" hint for better user guidance
- Changes affect all API provider tests: OpenAI, Anthropic, Gemini, ZAI, and OpenRouter
- This ensures tests align with improved error messaging for missing API keys
- Updated test assertion to match improved error message text
- Changed expectation from generic "not found or is empty" to more specific "not found (check config or environment)"
- This aligns the test with enhanced error messaging that provides clearer guidance to users when environment variables are missing
- Remove group_id generation and direct emit_error/emit_warning calls from grep function
- Consolidate error handling to collect error messages in a single variable
- Move UI message emission to the end of the function to ensure single emission point
- Add error field to GrepOutput model to return error information to caller
- Remove unused imports for emit_error, emit_warning, and generate_group_id
- Restructure exception handling to set error_message instead of immediate emission
- Clean up the order of operations to prepare data first, then emit messages consistently
…ards compatibility

- Add optional session_title field to SessionMetadata dataclass
- Only serialize session_title when not None for backwards compatibility
- Preserve existing title when saving session without providing new title
- Display session titles in CLI autosave session listings
- Update session tuple unpacking to include title field
…llback

- Add maybe_generate_session_title() function to generate concise titles (<10 words)
- Use dedicated PydanticAgent for title generation with configurable instructions
- Cache titles per session to avoid regeneration
- Implement fallback to truncated user prompt (first 10 words) when AI fails
- Support async and sync execution contexts with ThreadPoolExecutor
- Include session_title in auto_save_session_if_enabled() calls
… mode

- Generate session titles after first successful non-command response
- Skip title generation for commands (starting with /)
- Add warning message display when title generation fails
- Apply to both interactive_mode() and prompt_then_interactive_mode()
- Maintain silent operation on success to avoid noise
- Add test_save_session_with_title to verify title persistence
- Verify title is saved to metadata JSON
- Verify title persists when saving session without providing new title
- Update existing tests to verify backwards compatibility (title=None)
- Verify session_title not serialized when None
- Update test fixtures to include session_title parameter
- Remove obsolete mock_cleanup references
- Ensure session_title is set to None if not present in metadata JSON
- Update tuple unpacking in entries to accommodate session_title field
- Maintain compatibility with existing data structure
…TUI app

- Remove unused import statements in camoufox_manager and TUI app
- Reorganize code for better readability and maintainability
- Ensure consistent formatting across files
- Implement check for existing session title in metadata JSON before generating a new title
- Cache the retrieved title for future use to improve performance
- Ensure robust handling of metadata reading errors
…and link handling

- Add test to verify that Alt+M toggles multiline mode correctly, capturing output for both ON and OFF states.
- Update link handling test to ensure URLs remain unchanged when link parsing is disabled.
…oved title generation

- Introduce a new module for session title generation, encapsulating logic for creating concise titles based on user prompts.
- Replace previous title generation logic in config.py with calls to the new session title agent.
- Enhance error handling and caching mechanisms for session titles to ensure titles are generated once per session.
- Update relevant imports in main.py, TUI app, and other modules to utilize the new session title agent.
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.

10 participants