Commit Graph

28 Commits

  • Merge hooks and custom-tools into unified extensions system (#454)
    Breaking changes:
    - Settings: 'hooks' and 'customTools' arrays replaced with 'extensions'
    - CLI: '--hook' and '--tool' flags replaced with '--extension' / '-e'
    - API: HookMessage renamed to CustomMessage, role 'hookMessage' to 'custom'
    - API: FileSlashCommand renamed to PromptTemplate
    - API: discoverSlashCommands() renamed to discoverPromptTemplates()
    - Directories: commands/ renamed to prompts/ for prompt templates
    
    Migration:
    - Session version bumped to 3 (auto-migrates v2 sessions)
    - Old 'hookMessage' role entries converted to 'custom'
    
    Structural changes:
    - src/core/hooks/ and src/core/custom-tools/ merged into src/core/extensions/
    - src/core/slash-commands.ts renamed to src/core/prompt-templates.ts
    - examples/hooks/ and examples/custom-tools/ merged into examples/extensions/
    - docs/hooks.md and docs/custom-tools.md merged into docs/extensions.md
    
    New test coverage:
    - test/extensions-runner.test.ts (10 tests)
    - test/extensions-discovery.test.ts (26 tests)
    - test/prompt-templates.test.ts
  • Rework custom tools API with CustomToolContext
    - CustomAgentTool renamed to CustomTool
    - ToolAPI renamed to CustomToolAPI
    - ToolContext renamed to CustomToolContext
    - ToolSessionEvent renamed to CustomToolSessionEvent
    - Added CustomToolContext parameter to execute() and onSession()
    - CustomToolFactory now returns CustomTool<any, any> for type compatibility
    - dispose() replaced with onSession({ reason: 'shutdown' })
    - Added wrapCustomTool() to convert CustomTool to AgentTool
    - Session exposes setToolUIContext() instead of leaking internals
    - Fix ToolExecutionComponent to sync with toolOutputExpanded state
    - Update all custom tool examples for new API
  • refactor(coding-agent): fix compaction for branched sessions, consolidate hook context types
    Compaction API:
    - prepareCompaction() now takes (pathEntries, settings) only
    - CompactionPreparation restructured: removed cutPoint/messagesToKeep/boundaryStart, added turnPrefixMessages/isSplitTurn/previousSummary/fileOps/settings
    - compact() now takes (preparation, model, apiKey, customInstructions?, signal?)
    - Fixed token overflow by using getPath() instead of getEntries()
    
    Hook types:
    - HookEventContext renamed to HookContext
    - HookCommandContext removed, RegisteredCommand.handler takes (args, ctx)
    - HookContext now includes model field
    - SessionBeforeCompactEvent: removed previousCompactions/model, added branchEntries
    - SessionBeforeTreeEvent: removed model (use ctx.model)
    - HookRunner.initialize() added for modes to set up callbacks
  • Extract shared compaction/branch-summarization utils
    - New utils.ts with shared functions:
      - FileOperations type and createFileOps()
      - extractFileOpsFromMessage()
      - computeFileLists()
      - formatFileOperations()
      - serializeConversation()
      - SUMMARIZATION_SYSTEM_PROMPT
    
    - branch-summarization.ts now uses:
      - Serialization approach (conversation as text, not LLM messages)
      - completeSimple with system prompt
      - Shared utility functions
  • Use convertToLlm before serializing, include thinking, remove truncation
    - serializeConversation now takes Message[] (after convertToLlm)
    - Handles all custom message types via convertToLlm
    - Includes thinking blocks as [Assistant thinking]
    - Removes truncation of tool args and results (already token-budgeted)
  • Serialize conversation to text for summarization
    Instead of passing conversation as LLM messages (which makes the model
    try to continue it), serialize to text wrapped in <conversation> tags.
    
    - serializeConversation() formats messages as [User]/[Assistant]/[Tool result]
    - Tool calls shown as function(args) format
    - Tool results truncated to prevent bloat
    - Conversation wrapped in <conversation> tags in the prompt
  • Add system prompt to compaction summarization
    - SUMMARIZATION_SYSTEM_PROMPT explains the task clearly
    - Tells model to NOT continue conversation, ONLY output summary
    - Updated prompts to reference 'messages above' for clarity
    - Pass systemPrompt to completeSimple
  • Add file tracking and iterative summary merging to compaction
    - CompactionDetails type with readFiles/modifiedFiles
    - extractFileOperations collects from tool calls and previous compaction details
    - UPDATE_SUMMARIZATION_PROMPT for merging with previous summary
    - generateSummary now accepts previousSummary for iterative updates
    - compact() extracts files, passes previousSummary, returns details
    - Only merges from !fromHook compaction entries (backward compatible)
  • Add fromHook field to CompactionEntry and BranchSummaryEntry
    - fromHook: true = hook generated, skip file extraction
    - fromHook: undefined/false = pi generated, extract files (backward compatible)
    - branchWithSummary now accepts fromHook parameter
    - File extraction only runs for !entry.fromHook entries
  • Add preamble to branch summary for context
    Prepends: 'The user explored a different conversation branch before
    returning here. Summary of that exploration:'
    
    This helps the LLM understand the summary is background context from
    a different path, not the current thread being continued.
  • Fix branch summarization: use convertToLlm instead of messagesToText
    The old messagesToText only extracted text content, losing all tool calls.
    Now uses convertToLlm like compaction does, preserving the full conversation
    including tool calls, which is essential for generating useful summaries.
  • Fix common ancestor finding: iterate backwards to find deepest ancestor
    getPath returns root-first, so iterating forward found root as common
    ancestor instead of the deepest shared node. Now iterates backwards.
  • Use structured output format for compaction and branch summarization
    Both now use consistent sections:
    - Goal
    - Constraints & Preferences
    - Progress (Done/In Progress/Blocked)
    - Key Decisions
    - Next Steps
    - Critical Context (compaction only)
    
    Prompts instruct LLM to use EXACT format and preserve file paths/function names.
  • Append file lists to summary text for LLM context and TUI display
    Files are included both:
    - In summary text as <read-files>/<modified-files> tags (visible to LLM and TUI)
    - In details for structured access by code
  • Store file lists in BranchSummaryEntry.details for cumulative tracking
    - BranchSummaryResult now returns readFiles and modifiedFiles separately
    - BranchSummaryDetails type for details: { readFiles, modifiedFiles }
    - branchWithSummary accepts optional details parameter
    - Collect files from existing branch_summary.details when preparing entries
    - Files accumulate across nested branch summaries
  • Use XML tags for file operations in branch summary
    <read-files> and <modified-files> with one path per line
  • Fix file ops: Read (not modified) and Modified (edited or written)
    - Read: files only read, not modified
    - Modified: files that were edited OR written
    - Avoids duplicate listings when same file is read then edited
  • Use reserveTokens for branch summary (tokens left for prompt + response)
    - tokenBudget = contextWindow - reserveTokens
    - Default 16384, same as compaction
    - Consistent naming with CompactionSettings.reserveTokens
  • Use token-based maxTokens instead of fraction-based reserveFraction
    - BranchSummarySettings.maxTokens (default 100000) instead of reserveFraction
    - More intuitive and consistent with CompactionSettings.keepRecentTokens
  • Use AgentMessage in BranchPreparation and add BranchSummarySettings
    - BranchPreparation now uses AgentMessage[] instead of custom type
    - Reuse getMessageFromEntry pattern from compaction.ts
    - Add BranchSummarySettings with reserveFraction to settings.json
    - Add getBranchSummarySettings() to SettingsManager
    - Use settings for reserveFraction instead of hardcoded value
  • Add ReadonlySessionManager and refactor branch summarization
    - Add ReadonlySessionManager interface to session-manager.ts
    - Re-export from hooks/index.ts
    - Add collectEntriesForBranchSummary() to extract entries for summarization
    - Don't stop at compaction boundaries (include their summaries as context)
    - Add token budget support to prepareBranchEntries()
    - Walk entries newest-to-oldest to prioritize recent context
    - Use options object for generateBranchSummary()
    - Handle compaction entries as context summaries
    - Export new types: CollectEntriesResult, GenerateBranchSummaryOptions
  • Improve branch summarization with preparation and file ops extraction
    - Add prepareBranchEntries() to extract messages and file operations
    - Extract read/write/edit operations from tool calls
    - Append static file operations section to summary
    - Improve prompt for branch summarization
    - Skip toolResult messages (context already in assistant message)
    - Export new types: BranchPreparation, FileOperations
  • Refactor: move compaction code to src/core/compaction/
    - Move compaction.ts to src/core/compaction/compaction.ts
    - Extract branch summarization to src/core/compaction/branch-summarization.ts
    - Add index.ts to re-export all compaction utilities
    - Update all imports across the codebase