Commit graph

66 commits

Author SHA1 Message Date
Mario Zechner
c8d9382aaa 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
2025-12-30 22:42:18 +01:00
Mario Zechner
ba185b0571 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
2025-12-30 22:42:18 +01:00
Mario Zechner
9bba388ec5 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
2025-12-30 22:42:18 +01:00
Mario Zechner
d96375b5e5 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
2025-12-30 22:42:18 +01:00
Mario Zechner
705ba5d4f2 Improve compaction hooks: add signal, no timeout, SessionManager cleanup, docs 2025-12-24 13:54:05 +01:00
Mario Zechner
42d7d9d9b6 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
2025-12-22 18:18:38 +01:00
Mario Zechner
d5fd685901 Enable more biome lints and fix things 2025-12-21 22:56:20 +01:00
Mario Zechner
e7097d911a 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
2025-12-17 16:03:23 +01:00
Mario Zechner
bb445d24f1 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
2025-12-10 23:36:46 +01:00
Mario Zechner
3d35e7c469 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
2025-12-10 22:41:32 +01:00
Mario Zechner
7c553acd1e 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
2025-12-10 00:50:30 +01:00
Mario Zechner
04d59f31ea 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.
2025-12-09 22:17:12 +01:00
Mario Zechner
5a9d844f9a 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
2025-12-09 21:43:49 +01:00
Mario Zechner
dc9a4b0fe4 Rewrite RPC documentation with accurate types 2025-12-09 15:19:19 +01:00
Mario Zechner
3c8ab0280e Add get_messages RPC command 2025-12-09 14:37:16 +01:00
Mario Zechner
3559a43ba0 Rewrite RPC mode with typed protocol and client
- Move RPC files to modes/rpc/ directory
- Add properly typed RpcCommand and RpcResponse types
- Expose full AgentSession API via RPC commands:
  - State: get_state
  - Model: set_model, cycle_model, get_available_models
  - Thinking: set_thinking_level, cycle_thinking_level
  - Queue: set_queue_mode
  - Compaction: compact, set_auto_compaction
  - Bash: bash, abort_bash
  - Session: get_session_stats, export_html, switch_session, branch, etc.
- Add RpcClient class for programmatic access
- Rewrite tests to use RpcClient instead of raw process spawning
- All commands support optional correlation ID for request/response matching
2025-12-09 14:13:28 +01:00