Extensions: add pi.sendUserMessage() for sending user messages

Adds sendUserMessage() to the extension API, allowing extensions to send
actual user messages (role: user) rather than custom messages. Unlike
sendMessage(), this always triggers a turn and behaves as if the user
typed the message.

- Add SendUserMessageHandler type and sendUserMessage() to ExtensionAPI
- Wire handler through loader, runner, and all modes
- Implement via prompt() with expandPromptTemplates: false
- Add send-user-message.ts example with /ask, /steer, /followup commands
- Document in extensions.md

fixes #483
This commit is contained in:
Mario Zechner 2026-01-06 13:40:24 +01:00
parent f023af0dab
commit 7210086677
13 changed files with 222 additions and 1 deletions

View file

@ -788,6 +788,45 @@ export class AgentSession {
}
}
/**
* Send a user message to the agent. Always triggers a turn.
* When the agent is streaming, use deliverAs to specify how to queue the message.
*
* @param content User message content (string or content array)
* @param options.deliverAs Delivery mode when streaming: "steer" or "followUp"
*/
async sendUserMessage(
content: string | (TextContent | ImageContent)[],
options?: { deliverAs?: "steer" | "followUp" },
): Promise<void> {
// Normalize content to text string + optional images
let text: string;
let images: ImageContent[] | undefined;
if (typeof content === "string") {
text = content;
} else {
const textParts: string[] = [];
images = [];
for (const part of content) {
if (part.type === "text") {
textParts.push(part.text);
} else {
images.push(part);
}
}
text = textParts.join("\n");
if (images.length === 0) images = undefined;
}
// Use prompt() with expandPromptTemplates: false to skip command handling and template expansion
await this.prompt(text, {
expandPromptTemplates: false,
streamingBehavior: options?.deliverAs,
images,
});
}
/**
* Clear all queued messages and return them.
* Useful for restoring to editor when user aborts.