Commit Graph

61 Commits

  • Move exec to HookAPI, sessionManager/modelRegistry to HookEventContext
    Breaking changes:
    - HookEventContext now has sessionManager and modelRegistry (moved from SessionEventBase)
    - HookAPI now has exec() method (moved from HookEventContext/HookCommandContext)
    - HookRunner constructor takes sessionManager and modelRegistry as required params
    - Session events no longer include sessionManager/modelRegistry fields
    
    Hook code migration:
    - event.sessionManager -> ctx.sessionManager
    - event.modelRegistry -> ctx.modelRegistry
    - ctx.exec() -> pi.exec()
    
    Updated:
    - src/core/hooks/types.ts - type changes
    - src/core/hooks/runner.ts - constructor, createContext
    - src/core/hooks/loader.ts - add exec to HookAPI
    - src/core/sdk.ts - pass sessionManager/modelRegistry to HookRunner
    - src/core/agent-session.ts - remove sessionManager/modelRegistry from events
    - src/modes/* - remove setSessionFile calls, update events
    - examples/hooks/* - update to new API
  • Add Agent.prompt(AppMessage) overload for custom message types
    Instead of using continue() which validates roles, prompt() now accepts
    an AppMessage directly. This allows hook messages with role: 'hookMessage'
    to trigger proper agent loop with message events.
    
    - Add overloads: prompt(AppMessage) and prompt(string, attachments?)
    - sendHookMessage uses prompt(appMessage) instead of appendMessage+continue
  • Use proper HookAppMessage type instead of _hookData marker
    Following the same pattern as BashExecutionMessage:
    - HookAppMessage has role: 'hookMessage' with customType, content, display, details
    - isHookAppMessage() type guard for checking message type
    - messageTransformer converts to user message for LLM context
    - TUI checks isHookAppMessage() for rendering as CustomMessageComponent
    
    This makes the API clean for anyone building on AgentSession - they can
    use the type guard instead of knowing about internal marker fields.
  • Add emitLastMessage flag to agent.continue()
    When calling continue() with emitLastMessage=true, the agent loop
    emits message_start/message_end events for the last message in context.
    This allows messages added outside the loop (e.g., hook messages via
    sendHookMessage) to trigger proper TUI rendering.
    
    Changes across packages:
    - packages/ai: agentLoopContinue() accepts emitLastMessage parameter
    - packages/agent: Agent.continue(), transports updated to pass flag
    - packages/coding-agent: sendHookMessage passes true when triggerTurn
  • Hook commands: remove string return, use sendMessage() for prompting
    - Command handler now returns Promise<void> instead of Promise<string | undefined>
    - To trigger LLM response, use sendMessage() with triggerTurn: true
    - Simplify _tryExecuteHookCommand to return boolean
    
    Added example hook and slash command in .pi/:
    - .pi/hooks/test-command.ts - /greet command using sendMessage
    - .pi/commands/review.md - file-based /review command
  • Move hook command execution to AgentSession.prompt()
    Hook commands registered via pi.registerCommand() are now handled in
    AgentSession.prompt() alongside file-based slash commands. This:
    
    - Removes duplicate tryHandleHookCommand from interactive-mode and rpc-mode
    - All modes (interactive, RPC, print) share the same command handling logic
    - AgentSession._tryExecuteHookCommand() builds CommandContext using:
      - UI context from hookRunner (set by mode)
      - sessionManager, modelRegistry from AgentSession
      - sendMessage via sendHookMessage
      - exec via exported execCommand
    - Handler returning string uses it as prompt, undefined returns early
    
    Also:
    - Export execCommand from hooks/runner.ts
    - Add getUIContext() and getHasUI() to HookRunner
    - Make HookRunner.emitError() public for error reporting
  • Hook API: replace send() with sendMessage(), add appendEntry() and registerCommand()
    Breaking changes to Hook API:
    - pi.send(text, attachments?) replaced with pi.sendMessage(message, triggerTurn?)
      - Creates CustomMessageEntry instead of user messages
      - Properly handles queuing during streaming via agent loop
      - Supports optional turn triggering when idle
    - New pi.appendEntry(customType, data?) for hook state persistence
    - New pi.registerCommand(name, options) for custom slash commands
    - Handler types renamed: SendHandler -> SendMessageHandler, new AppendEntryHandler
    
    Implementation:
    - AgentSession.sendHookMessage() handles all three cases:
      - Streaming: queues message with _hookData marker, agent loop processes it
      - Not streaming + triggerTurn: appends to state/session, calls agent.continue()
      - Not streaming + no trigger: appends to state/session only
    - message_end handler routes based on _hookData presence to correct persistence
    - HookRunner gains getRegisteredCommands() and getCommand() methods
    
    New types: HookMessage<T>, RegisteredCommand, CommandContext
  • Refactor SessionEventBase to pass sessionManager and modelRegistry
    Breaking changes to hook types:
    - SessionEventBase now passes sessionManager and modelRegistry directly
    - before_compact: passes preparation, previousCompactions (newest first)
    - before_switch: has targetSessionFile; switch: has previousSessionFile
    - Removed resolveApiKey (use modelRegistry.getApiKey())
    - getSessionFile() returns string | undefined for in-memory sessions
    
    Updated:
    - All session event emissions in agent-session.ts
    - Hook examples (custom-compaction.ts, auto-commit-on-exit.ts, confirm-destructive.ts)
    - Tests (compaction-hooks.test.ts, compaction-hooks-example.test.ts)
    - export-html.ts guards for in-memory sessions
  • Make CompactionEntry and CompactionResult generic with details field
    - CompactionEntry<T> and CompactionResult<T> now have optional details?: T
    - appendCompaction() accepts optional details parameter
    - Hooks can return compaction.details to store custom data
    - Enables structured compaction with ArtifactIndex (see #314)
    - Fix CompactionResult export location (now from compaction.ts)
    - Update plan with remaining compaction refactor items
  • Session tree: simplify types, add branching API, comprehensive tests
    Types:
    - SessionEntryBase with type field, extended by all entry types
    - CustomEntry for hooks (type: 'custom', customType, data)
    - Remove XXXContent types and TreeNode (redundant)
    
    API:
    - Rename saveXXX to appendXXX with JSDoc explaining tree semantics
    - Rename branchInPlace to branch() with better docs
    - Add createBranchedSession(leafId) replacing index-based version
    - Add getTree() returning SessionTreeNode[] for tree traversal
    - Add appendCustomEntry(customType, data) for hooks
    
    Tests:
    - tree-traversal.test.ts: 28 tests covering append, getPath, getTree,
      branch, branchWithSummary, createBranchedSession
    - save-entry.test.ts: custom entry integration
    
    Docs:
    - Class-level JSDoc explaining append-only tree model
    - Method docs explaining leaf advancement and branching
    - CHANGELOG.md entry for all changes
  • Fix SessionEntry type to exclude SessionHeader
    - SessionEntry now only contains conversation entries (messages, compaction, etc.)
    - SessionHeader is separate, not part of SessionEntry
    - FileEntry = SessionHeader | SessionEntry (for file storage)
    - getEntries() filters out header, returns SessionEntry[]
    - Added getHeader() for accessing session metadata
    - Updated compaction and tests to not expect header in entries
    - Updated mom package to use FileEntry for internal storage
  • Session tree structure with id/parentId linking
    - Add TreeNode base type with id, parentId, timestamp
    - Add *Content types for clean input/output separation
    - Entry types are now TreeNode & *Content intersections
    - SessionManager assigns id/parentId on save, tracks leafId
    - Add migrateSessionEntries() for v1 to v2 conversion
    - Migration runs on load, rewrites file
    - buildSessionContext() uses tree traversal from leaf
    - Compaction returns CompactionResult (content only)
    - Hooks return compaction content, not full entries
    - Add firstKeptEntryId to before_compact hook event
    - Update mom package for tree fields
    - Better error messages for compaction failures
  • Merge pull request #346 from ronyrus/main
    Improve error message when `apiKey` or `model` are absent
  • Rename /clear to /new, update hook events to before_new/new
    Closes #305 - took direct rename approach instead of alias system
    
    Thanks @mitsuhiko for the nudge!
  • Refactor OAuth/API key handling: AuthStorage and ModelRegistry
    - Add AuthStorage class for credential storage (auth.json)
    - Add ModelRegistry class for model management with API key resolution
    - Add discoverAuthStorage() and discoverModels() discovery functions
    - Add migration from legacy oauth.json and settings.json apiKeys to auth.json
    - Remove configureOAuthStorage, defaultGetApiKey, findModel, discoverAvailableModels
    - Remove apiKeys from Settings type and SettingsManager methods
    - Rename getOAuthPath to getAuthPath
    - Update SDK, examples, docs, tests, and mom package
    
    Fixes #296
  • WIP: Rename model-config.ts to models-json.ts
    - loadCustomModels now takes file path instead of agentDir
  • feat: Improve HTML export with markdown rendering and theme support
    - Render markdown server-side using marked (tables, headings, code blocks, etc.)
    - Honor user's chosen theme (light/dark) with appropriate color defaults
    - Add image rendering for user messages
    - Style code blocks with TUI-like ```language markers
  • Add before_compact hook event (closes #281) (#285)
    * Add before_compact hook event (closes #281)
    
    * Add compact hook event and documentation
    
    - Add compact event that fires after compaction completes
    - Update hooks.md with lifecycle diagram, field docs, and example
    - Add CHANGELOG entry
    - Add comprehensive test coverage (10 tests) for before_compact and compact events
    - Tests cover: event emission, cancellation, custom entry, error handling, multiple hooks
  • Add before/after session events with cancellation support
    - Merge branch event into session with before_branch/branch reasons
    - Add before_switch, before_clear, shutdown reasons
    - before_* events can be cancelled with { cancel: true }
    - Update RPC commands to return cancelled status
    - Add shutdown event on process exit
    - New example hooks: confirm-destructive, dirty-repo-guard, auto-commit-on-exit
    
    fixes #278
  • Fix session-manager simplification issues
    - Remove unused inspector import from session-manager.ts
    - Remove dead code in _persist()
    - Update tests for simplified SessionHeader
    - Update mom context.ts: remove unused AgentState import, fix startSession(), rename isEnabled to isPersisted
  • fix(coding-agent): clamp thinking level to model capabilities
    - setThinkingLevel() now clamps xhigh to high when model doesn't support it
    - Model changes automatically re-clamp the current thinking level
    - Fixed /model command to use session.setModel() instead of agent.setModel()
    - Footer and editor border color update after model/thinking changes
    
    Closes #253
  • feat: add xhigh thinking level support for gpt-5.2 models
    - Add supportsXhigh() function to ai package for checking xhigh support
    - Clamp xhigh to high for OpenAI models that don't support it
    - Update coding-agent to use centralized supportsXhigh()
    - gpt-5.2, gpt-5.2-codex now show xhigh in thinking selector
    
    Closes #236
  • feat: add xhigh thinking level support for gpt-5.2 and gpt-5.2-codex
    - Add XHIGH_MODELS constant and getAvailableThinkingLevels() to AgentSession
    - Update ThinkingSelectorComponent to accept availableLevels parameter
    - Both shift+tab cycling and /thinking command now show xhigh for supported models
    - Update types.ts documentation to list supported models
  • Custom tools with session lifecycle, examples for hooks and tools
    - Custom tools: TypeScript modules that extend pi with new tools
      - Custom TUI rendering via renderCall/renderResult
      - User interaction via pi.ui (select, confirm, input, notify)
      - Session lifecycle via onSession callback for state reconstruction
      - Examples: todo.ts, question.ts, hello.ts
    
    - Hook examples: permission-gate, git-checkpoint, protected-paths
    
    - Session lifecycle centralized in AgentSession
      - Works across all modes (interactive, print, RPC)
      - Unified session event for hooks (replaces session_start/session_switch)
    
    - Box component added to pi-tui
    
    - Examples bundled in npm and binary releases
    
    Fixes #190
  • Auto-retry on transient provider errors (overloaded, rate limit, 5xx)
    - Add retry logic with exponential backoff (2s, 4s, 8s) in AgentSession
    - Disable Anthropic SDK built-in retries (maxRetries: 0) to allow app-level handling
    - TUI shows retry status with Escape to cancel
    - RPC mode: add set_auto_retry, abort_retry commands and auto_retry_start/end events
    - Configurable via settings.json: retry.enabled, retry.maxRetries, retry.baseDelayMs
    - Exclude context overflow errors from retry (handled by compaction)
    
    fixes #157
  • Fix branch selector for single message and --no-session mode
    - Allow branch selector to open with single user message (changed <= 1 to === 0 check)
    - Support in-memory branching for --no-session mode (no files created)
    - Add isEnabled() getter to SessionManager
    - Update sessionFile getter to return null when sessions disabled
    - Update SessionSwitchEvent types to allow null session files
    - Add branching tests for single message and --no-session scenarios
    
    fixes #163
  • Add hooks system with pi.send() for external message injection
    - Hook discovery from ~/.pi/agent/hooks/, .pi/hooks/, --hook flag
    - Events: session_start, session_switch, agent_start/end, turn_start/end, tool_call, tool_result, branch
    - tool_call can block execution, tool_result can modify results
    - pi.send(text, attachments?) to inject messages from external sources
    - UI primitives: ctx.ui.select/confirm/input/notify
    - Context: ctx.exec(), ctx.cwd, ctx.sessionFile, ctx.hasUI
    - Docs shipped with npm package and binary builds
    - System prompt references docs folder
  • feat(coding-agent): implement hooks system
    - Add hooks infrastructure in core/hooks/ (loader, runner, types)
    - HookUIContext interface with mode-specific implementations
    - Interactive mode: TUI-based selector/input/confirm dialogs
    - RPC mode: JSON protocol for hook UI requests/responses
    - Print mode: no-op UI context (hooks run but can't prompt)
    - AgentSession.branch() now async, returns { selectedText, skipped }
    - Settings: hooks[] and hookTimeout configuration
    - Export hook types from package for hook authors
    
    Based on PR #147 proposal, adapted for new architecture.
  • Simplify compaction: remove proactive abort, use Agent.continue() for retry
    - Add agentLoopContinue() to pi-ai for resuming from existing context
    - Add Agent.continue() method and transport.continue() interface
    - Simplify AgentSession compaction to two cases: overflow (auto-retry) and threshold (no retry)
    - Remove proactive mid-turn compaction abort
    - Merge turn prefix summary into main summary
    - Add isCompacting property to AgentSession and RPC state
    - Block input during compaction in interactive mode
    - Show compaction count on session resume
    - Rename RPC.md to rpc.md for consistency
    
    Related to #128
  • feat(coding-agent): implement new compaction system with overflow recovery
    Phase 1: Updated compaction.ts
    - findCutPoint now returns CutPointResult with isSplitTurn and turnStartIndex
    - Can cut at user, assistant, or bashExecution messages (never tool results)
    - Added turnPrefixSummary support for split turns (parallel summarization)
    - estimateTokens helper for context size estimation
    
    Phase 2: Updated session-manager.ts
    - CompactionEntry now has optional turnPrefixSummary field
    - loadSessionFromEntries injects both summaries when turn was split
    
    Phase 3: Updated agent-session.ts
    - Overflow detection via isContextOverflow after agent_end
    - Proactive compaction check on turn_end before next LLM call
    - _abortingForCompaction flag to skip saving aborted messages
    - Auto-retry after overflow recovery or proactive compaction
    - New event fields: reason (overflow/threshold), willRetry
    
    Phase 4: Updated interactive-mode.ts
    - Shows reason in compaction status (Context overflow detected...)
    - Shows retry status after compaction
    
    Tests updated for new CutPointResult return type.
  • Fix auto-compaction TUI integration and cut point logic
    - Trigger auto-compaction after agent_end instead of during message_end
    - Show CompactionComponent after auto-compaction (same as manual /compact)
    - Fix cut point to include bash executions before kept user message
    - Stop backward scan at compaction, assistant, user, or toolResult boundaries
  • Add auto-compaction events to AgentSession
    - Add AgentSessionEvent type extending AgentEvent with auto_compaction_start/end
    - Emit events when auto-compaction starts and completes
    - TUI shows loader during auto-compaction with escape to cancel
    - Rebuilds chat UI when auto-compaction succeeds