@oh-my-pi/pi-agent-core 18.2.10 → 18.2.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.
- package/CHANGELOG.md +6 -0
- package/dist/types/types.d.ts +4 -1
- package/package.json +8 -8
- package/src/agent-loop.ts +32 -14
- package/src/types.ts +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.2.11] - 2026-09-23
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed background job completions interrupting foreground Bash and eval calls, which could cause those calls to be repeatedly moved into the background.
|
|
10
|
+
|
|
5
11
|
## [18.2.9] - 2026-09-22
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/dist/types/types.d.ts
CHANGED
|
@@ -243,7 +243,10 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
243
243
|
* Same rules as {@link hasIrcInterrupts}: non-consuming, only cuts
|
|
244
244
|
* *interruptible* waits short, ignored when interruptMode is "wait". Without
|
|
245
245
|
* it a completion notice sits behind an hour-long `hub wait` that the agent
|
|
246
|
-
* would have abandoned had it seen the notice.
|
|
246
|
+
* would have abandoned had it seen the notice. Unlike a peer IRC it never
|
|
247
|
+
* raises {@link ToolCallContext.steeringSignal}: a queued completion must
|
|
248
|
+
* not push ordinary foreground work (auto-background bash/eval) into the
|
|
249
|
+
* background.
|
|
247
250
|
*/
|
|
248
251
|
hasBackgroundCompletions?: () => boolean | Promise<boolean>;
|
|
249
252
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-agent-core",
|
|
4
|
-
"version": "18.2.
|
|
4
|
+
"version": "18.2.11",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Stencil Labs, Inc.",
|
|
@@ -35,16 +35,16 @@
|
|
|
35
35
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@oh-my-pi/pi-ai": "18.2.
|
|
39
|
-
"@oh-my-pi/pi-catalog": "18.2.
|
|
40
|
-
"@oh-my-pi/pi-natives": "18.2.
|
|
41
|
-
"@oh-my-pi/pi-utils": "18.2.
|
|
42
|
-
"@oh-my-pi/pi-wire": "18.2.
|
|
43
|
-
"@oh-my-pi/snapcompact": "18.2.
|
|
38
|
+
"@oh-my-pi/pi-ai": "18.2.11",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "18.2.11",
|
|
40
|
+
"@oh-my-pi/pi-natives": "18.2.11",
|
|
41
|
+
"@oh-my-pi/pi-utils": "18.2.11",
|
|
42
|
+
"@oh-my-pi/pi-wire": "18.2.11",
|
|
43
|
+
"@oh-my-pi/snapcompact": "18.2.11",
|
|
44
44
|
"@opentelemetry/api": "^1.9.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@oh-my-pi/omptype": "18.2.
|
|
47
|
+
"@oh-my-pi/omptype": "18.2.11",
|
|
48
48
|
"@opentelemetry/context-async-hooks": "^2.9.0",
|
|
49
49
|
"@opentelemetry/sdk-trace-base": "^2.9.0",
|
|
50
50
|
"@types/bun": "^1.3.14"
|
package/src/agent-loop.ts
CHANGED
|
@@ -2938,19 +2938,32 @@ async function executeToolCalls(
|
|
|
2938
2938
|
const checkAsideInterrupts = async (): Promise<void> => {
|
|
2939
2939
|
// Asides only fire once: an interrupt already recorded on interruptState
|
|
2940
2940
|
// must not re-abort, and (unlike steering) never re-consumes a queue.
|
|
2941
|
-
|
|
2941
|
+
// A completion-triggered record is the exception — it leaves the
|
|
2942
|
+
// cooperative signal down, so keep polling until a peer IRC escalates.
|
|
2943
|
+
if (!shouldInterruptImmediately || signal?.aborted) return;
|
|
2944
|
+
if (interruptState.triggered && steeringSoftController.signal.aborted) return;
|
|
2942
2945
|
// Peer IRC and background completions (finished jobs, exited supervised
|
|
2943
2946
|
// processes) hard-abort interruptible waits only; foreground tools keep
|
|
2944
|
-
// running (no partial side effects)
|
|
2945
|
-
// so backgroundable work can step aside for the queued notice.
|
|
2947
|
+
// running (no partial side effects).
|
|
2946
2948
|
let source: AsideInterruptSource | undefined;
|
|
2947
2949
|
if (hasIrcInterrupts && (await hasIrcInterrupts())) source = "irc";
|
|
2948
|
-
else if (hasBackgroundCompletions && (await hasBackgroundCompletions()))
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
interruptState.
|
|
2952
|
-
|
|
2953
|
-
|
|
2950
|
+
else if (!interruptState.triggered && hasBackgroundCompletions && (await hasBackgroundCompletions()))
|
|
2951
|
+
source = "background";
|
|
2952
|
+
if (!source) return;
|
|
2953
|
+
if (!interruptState.triggered) {
|
|
2954
|
+
interruptState.triggered = true;
|
|
2955
|
+
interruptState.source = source;
|
|
2956
|
+
ircAbortController.abort();
|
|
2957
|
+
}
|
|
2958
|
+
// Only an urgent aside raises the cooperative signal that makes
|
|
2959
|
+
// backgroundable foreground work (auto-background bash/eval) detach
|
|
2960
|
+
// itself. A peer waiting on an IRC is blocked on this batch; a finished
|
|
2961
|
+
// background job is not — its notice is an aside that injects at the
|
|
2962
|
+
// batch boundary either way. Detaching ordinary foreground work for it
|
|
2963
|
+
// also cascades: the freshly detached job's own completion re-triggers
|
|
2964
|
+
// this check for the next command, so millisecond-long commands chain
|
|
2965
|
+
// into separate background deliveries (#12869).
|
|
2966
|
+
if (source !== "background") steeringSoftController.abort();
|
|
2954
2967
|
};
|
|
2955
2968
|
|
|
2956
2969
|
const checkSteering = async (): Promise<void> => {
|
|
@@ -3296,10 +3309,11 @@ async function executeToolCalls(
|
|
|
3296
3309
|
|
|
3297
3310
|
// While tool calls are in flight, queued steering or interrupting IRC would
|
|
3298
3311
|
// otherwise wait out the tools' own window. Poll only non-consuming queues:
|
|
3299
|
-
// detection hard-aborts interruptible waits (running or not yet started)
|
|
3300
|
-
// and soft-
|
|
3301
|
-
// dequeue below injects the message
|
|
3302
|
-
// mode; checkSteering is idempotent
|
|
3312
|
+
// detection hard-aborts interruptible waits (running or not yet started),
|
|
3313
|
+
// and steering/IRC additionally soft-signal cooperative tools
|
|
3314
|
+
// (auto-background bash), so the boundary dequeue below injects the message
|
|
3315
|
+
// promptly. Gated on immediate-interrupt mode; checkSteering is idempotent
|
|
3316
|
+
// (no-op once triggered).
|
|
3303
3317
|
const hasAsidePeek = hasIrcInterrupts !== undefined || hasBackgroundCompletions !== undefined;
|
|
3304
3318
|
const watchSteeringWhileRunning = shouldInterruptImmediately && (hasSteeringMessages !== undefined || hasAsidePeek);
|
|
3305
3319
|
const eventDrivenSteeringWatch =
|
|
@@ -3335,7 +3349,11 @@ async function executeToolCalls(
|
|
|
3335
3349
|
() => false,
|
|
3336
3350
|
);
|
|
3337
3351
|
if (!(await Promise.race([steeringChecked, watchAbortedFalse]))) return;
|
|
3338
|
-
|
|
3352
|
+
// Stop once the cooperative signal is up — steering and IRC
|
|
3353
|
+
// have nothing left to escalate. A completion-only trigger
|
|
3354
|
+
// leaves it down, so keep watching: a genuine steer arriving
|
|
3355
|
+
// afterwards must still reach foreground tools.
|
|
3356
|
+
if (steeringWatchSignal.aborted || steeringSoftController.signal.aborted) return;
|
|
3339
3357
|
if (!(await Promise.race([steeringQueued, watchAbortedFalse]))) return;
|
|
3340
3358
|
}
|
|
3341
3359
|
})()
|
package/src/types.ts
CHANGED
|
@@ -300,7 +300,10 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
300
300
|
* Same rules as {@link hasIrcInterrupts}: non-consuming, only cuts
|
|
301
301
|
* *interruptible* waits short, ignored when interruptMode is "wait". Without
|
|
302
302
|
* it a completion notice sits behind an hour-long `hub wait` that the agent
|
|
303
|
-
* would have abandoned had it seen the notice.
|
|
303
|
+
* would have abandoned had it seen the notice. Unlike a peer IRC it never
|
|
304
|
+
* raises {@link ToolCallContext.steeringSignal}: a queued completion must
|
|
305
|
+
* not push ordinary foreground work (auto-background bash/eval) into the
|
|
306
|
+
* background.
|
|
304
307
|
*/
|
|
305
308
|
hasBackgroundCompletions?: () => boolean | Promise<boolean>;
|
|
306
309
|
|