Add session management and agent state methods to hooks API

HookAPI additions:
- pi.newSession(options?) - create new session with optional setup callback
- pi.branch(entryId) - branch from a specific entry
- pi.navigateTree(targetId, options?) - navigate the session tree

HookContext additions:
- ctx.isIdle() - check if agent is streaming
- ctx.waitForIdle() - wait for agent to finish
- ctx.abort() - abort current operation
- ctx.hasQueuedMessages() - check for queued user messages

These enable hooks to programmatically manage sessions (handoff, templates)
and check agent state before showing interactive UI.

Fixes #388
This commit is contained in:
Mario Zechner 2026-01-01 23:56:24 +01:00
parent 484d7e06bb
commit ccdd7bd283
9 changed files with 355 additions and 14 deletions

View file

@ -540,6 +540,44 @@ if (ctx.model) {
}
```
### ctx.isIdle()
Returns `true` if the agent is not currently streaming. Useful for hooks that need to wait or check state:
```typescript
if (ctx.isIdle()) {
// Agent is not processing
}
```
### ctx.waitForIdle()
Wait for the agent to finish streaming:
```typescript
await ctx.waitForIdle();
// Agent is now idle
```
### ctx.abort()
Abort the current agent operation:
```typescript
await ctx.abort();
```
### ctx.hasQueuedMessages()
Check if there are messages queued (user typed while agent was streaming):
```typescript
if (ctx.hasQueuedMessages()) {
// Skip interactive prompt, let queued message take over
return;
}
```
## HookAPI Methods
### pi.on(event, handler)
@ -655,6 +693,47 @@ const result = await pi.exec("git", ["status"], {
// result.stdout, result.stderr, result.code, result.killed
```
### pi.newSession(options?)
Start a new session, optionally with a setup callback to initialize it:
```typescript
await pi.newSession({
parentSession: ctx.sessionManager.getSessionFile(), // Track lineage
setup: async (sessionManager) => {
// sessionManager is writable, can append messages
sessionManager.appendMessage({
role: "user",
content: [{ type: "text", text: "Context from previous session..." }]
});
}
});
```
Returns `{ cancelled: boolean }` - cancelled if a `session_before_switch` hook cancelled.
### pi.branch(entryId)
Branch from a specific entry, creating a new session file:
```typescript
const result = await pi.branch(entryId);
if (!result.cancelled) {
// Branched successfully
}
```
### pi.navigateTree(targetId, options?)
Navigate to a different point in the session tree (in-place):
```typescript
const result = await pi.navigateTree(targetId, { summarize: true });
if (!result.cancelled) {
// Navigated successfully
}
```
## Examples
### Permission Gate