Commit graph

10 commits

Author SHA1 Message Date
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
3ecaaa5937 Fix CustomMessageEntry content type to match UserMessage
content: string | (TextContent | ImageContent)[]

This matches the UserMessage type from pi-ai, so content can be
passed directly to AppMessage without conversion.
2025-12-30 22:42:18 +01:00
Mario Zechner
9da36e5ac6 Add CustomMessageEntry for hook-injected messages in LLM context
- CustomMessageEntry<T> type with customType, content, display, details
- appendCustomMessageEntry() in SessionManager
- buildSessionContext() includes custom_message entries as user messages
- Exported CustomEntry and CustomMessageEntry from main index

CustomEntry is for hook state (not in context).
CustomMessageEntry is for hook-injected content (in context).
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
efb1036d8e Improve CustomEntry docs and make it generic
- Add detailed doc comment explaining purpose (hook state persistence)
- Make CustomEntry<T = unknown> generic
- Clarify difference from CustomMessageEntry in plan
- Update changelog
2025-12-30 22:42:18 +01:00
Mario Zechner
e841942377 Use CompactionResult type for hook compaction return value
- Import CompactionResult in hooks/types.ts
- Replace inline type with CompactionResult for SessionEventResult.compaction
- Add labels feature to changelog
2025-12-30 22:42:18 +01:00
Mario Zechner
9e68a59fed Add label support for session entries
- Add LabelEntry type with targetId and label (string | undefined)
- Add labelsById map built on load via linear scan
- Add getLabel(id) and appendLabelChange(targetId, label) methods
- Add label field to SessionTreeNode, populated by getTree()
- Update createBranchedSession to preserve labels for entries on path
- Labels are ignored by buildSessionContext (not sent to LLM)
- Add comprehensive tests for label functionality
2025-12-30 22:42:18 +01:00
Mario Zechner
898607f742 Update session-tree-plan.md with remaining work 2025-12-30 22:42:18 +01:00
Mario Zechner
c58d5f20a4 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
2025-12-30 22:42:17 +01:00