aboutsummaryrefslogtreecommitdiff
path: root/crates/dinggerd/assets/pi/pi-agent-state.ts
diff options
context:
space:
mode:
Diffstat (limited to 'crates/dinggerd/assets/pi/pi-agent-state.ts')
-rw-r--r--crates/dinggerd/assets/pi/pi-agent-state.ts72
1 files changed, 70 insertions, 2 deletions
diff --git a/crates/dinggerd/assets/pi/pi-agent-state.ts b/crates/dinggerd/assets/pi/pi-agent-state.ts
index ff893e7..4c21afe 100644
--- a/crates/dinggerd/assets/pi/pi-agent-state.ts
+++ b/crates/dinggerd/assets/pi/pi-agent-state.ts
@@ -69,7 +69,34 @@ function updateSessionFile(ctx: any): void {
}
}
-function report(state: AgentState, message?: string): Promise<void> {
+// The agent's importance (/importance): it orders agents within a status
+// in dingger's list and jump, and a low agent makes no sound. Saved in the
+// session (a custom entry, never sent to the model), so it comes back with
+// the conversation: on /resume, `pi --session`, and dingger's restore.
+// Other extensions can follow it on the event bus: `dingger:importance`,
+// `{ level }`, at session start and on every change.
+type Importance = "low" | "normal" | "high";
+const importanceLevels: Importance[] = ["high", "normal", "low"];
+const importanceEntry = "dingger-importance";
+let importance: Importance = "normal";
+
+function savedImportance(ctx: any): Importance {
+ try {
+ const entries = ctx?.sessionManager?.getEntries?.() ?? [];
+ for (let i = entries.length - 1; i >= 0; i--) {
+ const entry = entries[i];
+ if (entry?.type === "custom" && entry.customType === importanceEntry) {
+ const level = entry.data?.level;
+ return importanceLevels.includes(level) ? level : "normal";
+ }
+ }
+ } catch {
+ // An unreadable session: the default.
+ }
+ return "normal";
+}
+
+function report(state: AgentState | undefined, message?: string): Promise<void> {
return sendRequest({
id: `${source}:${Date.now()}:${Math.random().toString(36).slice(2)}`,
method: "pane.report_agent",
@@ -77,8 +104,9 @@ function report(state: AgentState, message?: string): Promise<void> {
pane_id: paneId!,
source,
agent: "pi",
- state,
+ ...(state ? { state } : {}),
message,
+ importance,
seq: Date.now() * 1000,
...(sessionFile ? { agent_session_path: sessionFile } : {}),
},
@@ -161,6 +189,43 @@ export default function (pi) {
publishState();
});
+ function showImportance(ctx: any) {
+ ctx?.ui?.setStatus?.("dingger-importance", importance === "normal" ? undefined : `importance: ${importance}`);
+ pi.events.emit("dingger:importance", { level: importance });
+ }
+
+ pi.registerCommand("importance", {
+ description: "Set this agent's importance in dingger: high, normal, or low",
+ // None once a level is typed out, so Enter runs the command at once.
+ getArgumentCompletions: (prefix: string) =>
+ importanceLevels.includes(prefix.trim() as Importance)
+ ? null
+ : importanceLevels
+ .filter((level) => level.startsWith(prefix.trim()))
+ .map((level) => ({ value: level, label: level })),
+ handler: async (args: string, ctx: any) => {
+ const wanted = args.trim();
+ if (!wanted) {
+ ctx.ui.notify(`importance: ${importance}`, "info");
+ return;
+ }
+ if (!importanceLevels.includes(wanted as Importance)) {
+ ctx.ui.notify("importance is high, normal, or low", "error");
+ return;
+ }
+ if (wanted !== importance) {
+ importance = wanted as Importance;
+ pi.appendEntry(importanceEntry, { level: importance });
+ showImportance(ctx);
+ // Without a state: the state stays as last reported.
+ if (enabled()) {
+ void report(undefined);
+ }
+ }
+ ctx.ui.notify(`importance: ${importance}`, "info");
+ },
+ });
+
pi.on("session_start", async (event, ctx) => {
// TUI only: RPC/JSON/print modes are headless.
if (ctx?.mode !== "tui") {
@@ -169,6 +234,9 @@ export default function (pi) {
// A reload can replace this extension mid-run without emitting another agent_start.
agentActive = ctx?.isIdle?.() === false;
updateSessionFile(ctx);
+ // Each session has its own: /new starts at normal, /resume brings its own back.
+ importance = savedImportance(ctx);
+ showImportance(ctx);
publishState(true);
});