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.ts37
1 files changed, 37 insertions, 0 deletions
diff --git a/crates/dinggerd/assets/pi/pi-agent-state.ts b/crates/dinggerd/assets/pi/pi-agent-state.ts
index e4e357d..fc70638 100644
--- a/crates/dinggerd/assets/pi/pi-agent-state.ts
+++ b/crates/dinggerd/assets/pi/pi-agent-state.ts
@@ -116,6 +116,9 @@ function savedImportance(ctx: any): Importance {
// it comes back when the session does after a crash, a restart, or
// `pi --session`.
let draft = "";
+// How full the context window is, in percent, as pi's footer shows it;
+// "" when unknown (right after compacting, before the next reply).
+let context = "";
const draftDir = path.join(path.dirname(socketPath), "drafts");
// Enough to find the agent by it; the file keeps all of it.
const reportedDraftChars = 500;
@@ -178,6 +181,7 @@ async function report(state: AgentState | undefined, message?: string): Promise<
extension: extensionVersion,
...(controlListening ? { control: controlPath } : {}),
draft: draft.slice(0, reportedDraftChars),
+ context,
seq: Date.now() * 1000,
...(sessionFile ? { agent_session_path: sessionFile } : {}),
},
@@ -342,6 +346,26 @@ export default function (pi) {
void report(undefined);
}
+ /** Report how full the context window is, when that changed. */
+ function checkContext(ctx: any, quiet = false): void {
+ let next = "";
+ try {
+ const percent = ctx?.getContextUsage?.()?.percent;
+ if (typeof percent === "number" && Number.isFinite(percent)) {
+ next = percent.toFixed(1);
+ }
+ } catch {
+ return;
+ }
+ if (next === context) {
+ return;
+ }
+ context = next;
+ if (!quiet) {
+ void report(undefined);
+ }
+ }
+
function checkDraftSoon(): void {
if (draftTimer) {
clearTimeout(draftTimer);
@@ -469,6 +493,8 @@ export default function (pi) {
// Each session has its own: /new starts at normal, /resume brings its own back.
importance = savedImportance(ctx);
announceImportance();
+ // The report below carries it.
+ checkContext(ctx, true);
publishState(true);
});
@@ -481,6 +507,15 @@ export default function (pi) {
checkDraftSoon();
});
+ // Each message fills the context (a prompt by pi's estimate, a reply by
+ // its usage); compacting empties it; another model or branch changes it.
+ for (const event of ["message_end", "session_compact", "model_select", "session_tree"]) {
+ pi.on(event, (_event, ctx) => {
+ latestCtx = ctx;
+ checkContext(ctx);
+ });
+ }
+
pi.on("agent_settled", (_event, ctx) => {
latestCtx = ctx;
if (ctx?.isIdle?.() !== true) {
@@ -488,6 +523,8 @@ export default function (pi) {
}
agentActive = false;
+ // The last reply's usage: message_end comes before pi counts it.
+ checkContext(ctx);
publishState();
// Escape puts queued messages back into the input box.
checkDraftSoon();