mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 13:03:42 +00:00
Move skill command handling to AgentSession, update docs
- Skill commands (/skill:name) now expanded in AgentSession instead of interactive mode, enabling them in RPC and print modes - Input event can now intercept /skill:name before expansion - Updated extensions.md with clearer input event docs and processing order - Updated rpc.md: hook -> extension terminology, added skill expansion mentions - Added PR attribution to changelog entries for #761
This commit is contained in:
parent
3e5d91f287
commit
b4a05cbcab
7 changed files with 211 additions and 420 deletions
|
|
@ -256,7 +256,9 @@ pi starts
|
|||
▼
|
||||
user sends prompt ─────────────────────────────────────────┐
|
||||
│ │
|
||||
├─► input (can transform or handle completely) │
|
||||
├─► (extension commands checked first, bypass if found) │
|
||||
├─► input (can intercept, transform, or handle) │
|
||||
├─► (skill/template expansion if not handled) │
|
||||
├─► before_agent_start (can inject message, modify system prompt)
|
||||
├─► agent_start │
|
||||
│ │
|
||||
|
|
@ -579,25 +581,49 @@ pi.on("user_bash", (event, ctx) => {
|
|||
|
||||
#### input
|
||||
|
||||
Fired when user input is received, before agent processing. Can transform or handle completely.
|
||||
Fired when user input is received, after extension commands are checked but before skill and template expansion. The event sees the raw input text, so `/skill:foo` and `/template` are not yet expanded.
|
||||
|
||||
**Processing order:**
|
||||
1. Extension commands (`/cmd`) checked first - if found, handler runs and input event is skipped
|
||||
2. `input` event fires - can intercept, transform, or handle
|
||||
3. If not handled: skill commands (`/skill:name`) expanded to skill content
|
||||
4. If not handled: prompt templates (`/template`) expanded to template content
|
||||
5. Agent processing begins (`before_agent_start`, etc.)
|
||||
|
||||
```typescript
|
||||
pi.on("input", async (event, ctx) => {
|
||||
// event.text, event.images, event.source ("interactive" | "rpc" | "extension")
|
||||
// event.text - raw input (before skill/template expansion)
|
||||
// event.images - attached images, if any
|
||||
// event.source - "interactive" (typed), "rpc" (API), or "extension" (via sendUserMessage)
|
||||
|
||||
// Transform: rewrite input before expansion
|
||||
if (event.text.startsWith("?quick "))
|
||||
return { action: "transform", text: `Respond briefly: ${event.text.slice(7)}` };
|
||||
|
||||
// Handle: respond without LLM (extension shows its own feedback)
|
||||
if (event.text === "ping") {
|
||||
ctx.ui.notify("pong", "info"); // Extension handles its own feedback
|
||||
return { action: "handled" }; // Skip LLM
|
||||
ctx.ui.notify("pong", "info");
|
||||
return { action: "handled" };
|
||||
}
|
||||
|
||||
return { action: "continue" }; // Default: pass through
|
||||
// Route by source: skip processing for extension-injected messages
|
||||
if (event.source === "extension") return { action: "continue" };
|
||||
|
||||
// Intercept skill commands before expansion
|
||||
if (event.text.startsWith("/skill:")) {
|
||||
// Could transform, block, or let pass through
|
||||
}
|
||||
|
||||
return { action: "continue" }; // Default: pass through to expansion
|
||||
});
|
||||
```
|
||||
|
||||
**Results:** `continue` (pass through), `transform` (modify text/images), `handled` (skip LLM). Transforms chain; first "handled" wins. See [input-transform.ts](../examples/extensions/input-transform.ts).
|
||||
**Results:**
|
||||
- `continue` - pass through unchanged (default if handler returns nothing)
|
||||
- `transform` - modify text/images, then continue to expansion
|
||||
- `handled` - skip agent entirely (first handler to return this wins)
|
||||
|
||||
Transforms chain across handlers. See [input-transform.ts](../examples/extensions/input-transform.ts).
|
||||
|
||||
## ExtensionContext
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ With images:
|
|||
|
||||
If the agent is streaming and no `streamingBehavior` is specified, the command returns an error.
|
||||
|
||||
**Extension commands**: If the message is a hook command (e.g., `/mycommand`), it executes immediately even during streaming. Extension commands manage their own LLM interaction via `pi.sendMessage()`.
|
||||
**Extension commands**: If the message is an extension command (e.g., `/mycommand`), it executes immediately even during streaming. Extension commands manage their own LLM interaction via `pi.sendMessage()`.
|
||||
|
||||
**Prompt templates**: File-based prompt templates (from `.md` files) are expanded before sending/queueing.
|
||||
**Input expansion**: Skill commands (`/skill:name`) and prompt templates (`/template`) are expanded before sending/queueing.
|
||||
|
||||
Response:
|
||||
```json
|
||||
|
|
@ -65,7 +65,7 @@ The `images` field is optional. Each image uses `ImageContent` format with base6
|
|||
|
||||
#### steer
|
||||
|
||||
Queue a steering message to interrupt the agent mid-run. Delivered after current tool execution, remaining tools are skipped. File-based prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
|
||||
Queue a steering message to interrupt the agent mid-run. Delivered after current tool execution, remaining tools are skipped. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
|
||||
|
||||
```json
|
||||
{"type": "steer", "message": "Stop and do this instead"}
|
||||
|
|
@ -80,7 +80,7 @@ See [set_steering_mode](#set_steering_mode) for controlling how steering message
|
|||
|
||||
#### follow_up
|
||||
|
||||
Queue a follow-up message to be processed after the agent finishes. Delivered only when agent has no more tool calls or steering messages. File-based prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
|
||||
Queue a follow-up message to be processed after the agent finishes. Delivered only when agent has no more tool calls or steering messages. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
|
||||
|
||||
```json
|
||||
{"type": "follow_up", "message": "After you're done, also do this"}
|
||||
|
|
@ -108,7 +108,7 @@ Response:
|
|||
|
||||
#### new_session
|
||||
|
||||
Start a fresh session. Can be cancelled by a `session_before_switch` hook.
|
||||
Start a fresh session. Can be cancelled by a `session_before_switch` extension event handler.
|
||||
|
||||
```json
|
||||
{"type": "new_session"}
|
||||
|
|
@ -124,7 +124,7 @@ Response:
|
|||
{"type": "response", "command": "new_session", "success": true, "data": {"cancelled": false}}
|
||||
```
|
||||
|
||||
If a hook cancelled:
|
||||
If an extension cancelled:
|
||||
```json
|
||||
{"type": "response", "command": "new_session", "success": true, "data": {"cancelled": true}}
|
||||
```
|
||||
|
|
@ -525,7 +525,7 @@ Response:
|
|||
|
||||
#### switch_session
|
||||
|
||||
Load a different session file. Can be cancelled by a `before_switch` hook.
|
||||
Load a different session file. Can be cancelled by a `session_before_switch` extension event handler.
|
||||
|
||||
```json
|
||||
{"type": "switch_session", "sessionPath": "/path/to/session.jsonl"}
|
||||
|
|
@ -536,14 +536,14 @@ Response:
|
|||
{"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": false}}
|
||||
```
|
||||
|
||||
If a hook cancelled the switch:
|
||||
If an extension cancelled the switch:
|
||||
```json
|
||||
{"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": true}}
|
||||
```
|
||||
|
||||
#### fork
|
||||
|
||||
Create a new fork from a previous user message. Can be cancelled by a `before_fork` hook. Returns the text of the message being forked from.
|
||||
Create a new fork from a previous user message. Can be cancelled by a `session_before_fork` extension event handler. Returns the text of the message being forked from.
|
||||
|
||||
```json
|
||||
{"type": "fork", "entryId": "abc123"}
|
||||
|
|
@ -559,7 +559,7 @@ Response:
|
|||
}
|
||||
```
|
||||
|
||||
If a hook cancelled the fork:
|
||||
If an extension cancelled the fork:
|
||||
```json
|
||||
{
|
||||
"type": "response",
|
||||
|
|
@ -634,7 +634,7 @@ Events are streamed to stdout as JSON lines during agent operation. Events do NO
|
|||
| `auto_compaction_end` | Auto-compaction completes |
|
||||
| `auto_retry_start` | Auto-retry begins (after transient error) |
|
||||
| `auto_retry_end` | Auto-retry completes (success or final failure) |
|
||||
| `hook_error` | Hook threw an error |
|
||||
| `extension_error` | Extension threw an error |
|
||||
|
||||
### agent_start
|
||||
|
||||
|
|
@ -827,14 +827,14 @@ On final failure (max retries exceeded):
|
|||
}
|
||||
```
|
||||
|
||||
### hook_error
|
||||
### extension_error
|
||||
|
||||
Emitted when a hook throws an error.
|
||||
Emitted when an extension throws an error.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "hook_error",
|
||||
"hookPath": "/path/to/hook.ts",
|
||||
"type": "extension_error",
|
||||
"extensionPath": "/path/to/extension.ts",
|
||||
"event": "tool_call",
|
||||
"error": "Error message..."
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue