@monotykamary/pi-supervisor 0.5.9 → 0.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.ts +23 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monotykamary/pi-supervisor",
3
- "version": "0.5.9",
3
+ "version": "0.5.11",
4
4
  "description": "A pi extension that supervises the chat and steers it towards a defined outcome",
5
5
  "author": "tintinweb (forked by monotykamary)",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "devDependencies": {
41
41
  "@commitlint/cli": "21.0.1",
42
42
  "@commitlint/config-conventional": "21.0.1",
43
- "@earendil-works/pi-tui": "0.80.8",
43
+ "@earendil-works/pi-tui": "0.83.0",
44
44
  "@types/node": "25.9.1",
45
45
  "knip": "6.14.1",
46
46
  "lint-staged": "17.0.5",
package/src/index.ts CHANGED
@@ -79,6 +79,16 @@ export default function (pi: ExtensionAPI) {
79
79
  const state = new SupervisorStateManager(pi);
80
80
  const widgetState = createInitialState();
81
81
  let currentCtx: ExtensionContext | undefined;
82
+ let userInputEpoch = 0;
83
+
84
+ pi.on('input', (event) => {
85
+ if (event.source === 'interactive' || event.source === 'rpc') {
86
+ userInputEpoch++;
87
+ }
88
+ });
89
+ pi.on('before_agent_start', () => {
90
+ userInputEpoch++;
91
+ });
82
92
 
83
93
  const startSupervisionFromModel = async (
84
94
  outcome: string,
@@ -222,6 +232,7 @@ export default function (pi: ExtensionAPI) {
222
232
  pi.on('agent_settled', async (_event, ctx) => {
223
233
  currentCtx = ctx;
224
234
  if (!state.isActive()) return;
235
+ const inputEpochAtStart = userInputEpoch;
225
236
 
226
237
  const s = state.getState()!;
227
238
 
@@ -263,7 +274,7 @@ export default function (pi: ExtensionAPI) {
263
274
  const decision = await analyze(
264
275
  ctx,
265
276
  state.getState()!,
266
- true /* always idle at agent_end */,
277
+ true /* fully settled checkpoint */,
267
278
  ineffectivePattern,
268
279
  undefined,
269
280
  (accumulated) => {
@@ -276,6 +287,16 @@ export default function (pi: ExtensionAPI) {
276
287
  }
277
288
  );
278
289
 
290
+ // A real user prompt supersedes a decision computed from the preceding
291
+ // settled snapshot. Do not race that prompt or steer from stale context.
292
+ if (userInputEpoch !== inputEpochAtStart) {
293
+ updateUI(ctx, widgetState, state.getState(), {
294
+ type: 'watching',
295
+ reframeTier: state.getReframeTier(),
296
+ });
297
+ return;
298
+ }
299
+
279
300
  if (decision.action === 'steer' && decision.message) {
280
301
  state.incrementIdleSteers();
281
302
  state.addIntervention({
@@ -289,7 +310,7 @@ export default function (pi: ExtensionAPI) {
289
310
  message: decision.message,
290
311
  reframeTier: state.getReframeTier(),
291
312
  });
292
- pi.sendUserMessage(decision.message, { deliverAs: 'steer' });
313
+ pi.sendUserMessage(decision.message, { deliverAs: 'followUp' });
293
314
  } else if (decision.action === 'done') {
294
315
  state.resetIdleSteers();
295
316
  state.resetReframeTier();