feat(coding-agent): add input event for extension input interception (#761)

* feat(coding-agent): add input event for extension input interception

Extensions can now intercept, transform, or handle user input before the
agent processes it. Three result types: continue (pass through), transform
(modify text/images), handled (respond without LLM). Handlers chain
transforms and short-circuit on handled. Source field identifies origin.

* fix: make source public, use if/else over ternary

* fix: remove response field, extension handles own UI
This commit is contained in:
Nico Bailon 2026-01-15 17:41:56 -08:00 committed by GitHub
parent 012319e15a
commit 3e5d91f287
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 282 additions and 5 deletions

View file

@ -0,0 +1,43 @@
/**
* Input Transform Example - demonstrates the `input` event for intercepting user input.
*
* Start pi with this extension:
* pi -e ./examples/extensions/input-transform.ts
*
* Then type these inside pi:
* ?quick What is TypeScript? "Respond briefly: What is TypeScript?"
* ping "pong" (instant, no LLM)
* time current time (instant, no LLM)
*/
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.on("input", async (event, ctx) => {
// Source-based logic: skip processing for extension-injected messages
if (event.source === "extension") {
return { action: "continue" };
}
// Transform: ?quick prefix for brief responses
if (event.text.startsWith("?quick ")) {
const query = event.text.slice(7).trim();
if (!query) {
ctx.ui.notify("Usage: ?quick <question>", "warning");
return { action: "handled" };
}
return { action: "transform", text: `Respond briefly in 1-2 sentences: ${query}` };
}
// Handle: instant responses without LLM (extension shows its own feedback)
if (event.text.toLowerCase() === "ping") {
ctx.ui.notify("pong", "info");
return { action: "handled" };
}
if (event.text.toLowerCase() === "time") {
ctx.ui.notify(new Date().toLocaleString(), "info");
return { action: "handled" };
}
return { action: "continue" };
});
}