@oh-my-pi/pi-agent-core 18.2.6 → 18.2.8
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/THIRD-PARTY-NOTICES.txt +0 -37
- package/dist/types/agent.d.ts +5 -0
- package/dist/types/types.d.ts +10 -0
- package/package.json +8 -8
- package/src/agent-loop.ts +31 -21
- package/src/agent.ts +6 -0
- package/src/compaction/anthropic.ts +1 -1
- package/src/compaction/compaction-v2-streaming.ts +2 -2
- package/src/compaction/compaction.ts +1 -1
- package/src/compaction/openai.ts +3 -5
- package/src/types.ts +10 -0
package/THIRD-PARTY-NOTICES.txt
CHANGED
|
@@ -335,43 +335,6 @@ This license allows the work and adaptations of it to be shared and used
|
|
|
335
335
|
commercially, as long as it is attributed to Poppy Works. The font is bundled
|
|
336
336
|
here (crates/pi-natives/src/fonts/Silver.ttf) as a CJK/Unicode bitmap fallback.
|
|
337
337
|
|
|
338
|
-
-------------------------------------------------------------------------------
|
|
339
|
-
packages/utils/src/vendor/mermaid-ascii/NOTICE
|
|
340
|
-
|
|
341
|
-
This directory contains an in-house Mermaid-diagram-to-ASCII renderer adapted
|
|
342
|
-
from beautiful-mermaid (https://github.com/lukilabs/beautiful-mermaid), used
|
|
343
|
-
under the MIT License.
|
|
344
|
-
|
|
345
|
-
Copyright (c) 2026 Craft Docs
|
|
346
|
-
|
|
347
|
-
Only the ASCII rendering pipeline is ported (flowchart/state, sequence, class,
|
|
348
|
-
ER, and xychart diagrams); the SVG renderer and its `elkjs` graph-layout
|
|
349
|
-
dependency, the browser entry point, and the SVG theme/style modules were
|
|
350
|
-
dropped. Terminal display width is reimplemented on `Bun.stringWidth`, and
|
|
351
|
-
inline label formatting (HTML tags, markdown emphasis) is reduced to plain text
|
|
352
|
-
for ASCII output. Layout and edge-routing logic is preserved faithfully so
|
|
353
|
-
ASCII output matches the upstream package.
|
|
354
|
-
|
|
355
|
-
MIT License
|
|
356
|
-
|
|
357
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
358
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
359
|
-
in the Software without restriction, including without limitation the rights
|
|
360
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
361
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
362
|
-
furnished to do so, subject to the following conditions:
|
|
363
|
-
|
|
364
|
-
The above copyright notice and this permission notice shall be included in all
|
|
365
|
-
copies or substantial portions of the Software.
|
|
366
|
-
|
|
367
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
368
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
369
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
370
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
371
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
372
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
373
|
-
SOFTWARE.
|
|
374
|
-
|
|
375
338
|
-------------------------------------------------------------------------------
|
|
376
339
|
packages/coding-agent/src/markit/NOTICE
|
|
377
340
|
|
package/dist/types/agent.d.ts
CHANGED
|
@@ -256,6 +256,11 @@ export declare class Agent {
|
|
|
256
256
|
* Hook that peeks whether interrupting IRC asides are queued for the next boundary.
|
|
257
257
|
*/
|
|
258
258
|
hasIrcInterrupts?: AgentLoopConfig["hasIrcInterrupts"];
|
|
259
|
+
/**
|
|
260
|
+
* Hook that peeks whether background completions (jobs, supervised processes)
|
|
261
|
+
* are queued for the next boundary.
|
|
262
|
+
*/
|
|
263
|
+
hasBackgroundCompletions?: AgentLoopConfig["hasBackgroundCompletions"];
|
|
259
264
|
constructor(opts?: AgentOptions);
|
|
260
265
|
/**
|
|
261
266
|
* Get the current session ID used for provider caching.
|
package/dist/types/types.d.ts
CHANGED
|
@@ -236,6 +236,16 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
236
236
|
* The host owns message injection at the next boundary.
|
|
237
237
|
*/
|
|
238
238
|
hasIrcInterrupts?: () => boolean | Promise<boolean>;
|
|
239
|
+
/**
|
|
240
|
+
* Peeks whether a background completion (finished job, exited supervised
|
|
241
|
+
* process) is queued for aside injection at the next boundary.
|
|
242
|
+
*
|
|
243
|
+
* Same rules as {@link hasIrcInterrupts}: non-consuming, only cuts
|
|
244
|
+
* *interruptible* waits short, ignored when interruptMode is "wait". Without
|
|
245
|
+
* it a completion notice sits behind an hour-long `hub wait` that the agent
|
|
246
|
+
* would have abandoned had it seen the notice.
|
|
247
|
+
*/
|
|
248
|
+
hasBackgroundCompletions?: () => boolean | Promise<boolean>;
|
|
239
249
|
/**
|
|
240
250
|
* Returns follow-up messages to process after the agent would otherwise stop.
|
|
241
251
|
*
|
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.8",
|
|
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.8",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "18.2.8",
|
|
40
|
+
"@oh-my-pi/pi-natives": "18.2.8",
|
|
41
|
+
"@oh-my-pi/pi-utils": "18.2.8",
|
|
42
|
+
"@oh-my-pi/pi-wire": "18.2.8",
|
|
43
|
+
"@oh-my-pi/snapcompact": "18.2.8",
|
|
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.8",
|
|
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
|
@@ -2839,6 +2839,7 @@ async function executeToolCalls(
|
|
|
2839
2839
|
const {
|
|
2840
2840
|
hasSteeringMessages,
|
|
2841
2841
|
hasIrcInterrupts,
|
|
2842
|
+
hasBackgroundCompletions,
|
|
2842
2843
|
interruptMode = "immediate",
|
|
2843
2844
|
getToolContext,
|
|
2844
2845
|
|
|
@@ -2876,7 +2877,7 @@ async function executeToolCalls(
|
|
|
2876
2877
|
const interruptibleSignal: AbortSignal = signal
|
|
2877
2878
|
? AbortSignal.any([signal, steeringAbortController.signal, ircAbortController.signal])
|
|
2878
2879
|
: AbortSignal.any([steeringAbortController.signal, ircAbortController.signal]);
|
|
2879
|
-
const interruptState: { triggered: boolean; source?:
|
|
2880
|
+
const interruptState: { triggered: boolean; source?: AsideInterruptSource } = { triggered: false };
|
|
2880
2881
|
|
|
2881
2882
|
// Streamed messages were prepared (validation + `beforeToolCall`) before
|
|
2882
2883
|
// `message_end`, so hook revisions are already part of the message; anything
|
|
@@ -2927,19 +2928,22 @@ async function executeToolCalls(
|
|
|
2927
2928
|
};
|
|
2928
2929
|
});
|
|
2929
2930
|
|
|
2930
|
-
const
|
|
2931
|
-
//
|
|
2931
|
+
const checkAsideInterrupts = async (): Promise<void> => {
|
|
2932
|
+
// Asides only fire once: an interrupt already recorded on interruptState
|
|
2932
2933
|
// must not re-abort, and (unlike steering) never re-consumes a queue.
|
|
2933
2934
|
if (!shouldInterruptImmediately || signal?.aborted || interruptState.triggered) return;
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2935
|
+
// Peer IRC and background completions (finished jobs, exited supervised
|
|
2936
|
+
// processes) hard-abort interruptible waits only; foreground tools keep
|
|
2937
|
+
// running (no partial side effects) but get the cooperative soft signal
|
|
2938
|
+
// so backgroundable work can step aside for the queued notice.
|
|
2939
|
+
let source: AsideInterruptSource | undefined;
|
|
2940
|
+
if (hasIrcInterrupts && (await hasIrcInterrupts())) source = "irc";
|
|
2941
|
+
else if (hasBackgroundCompletions && (await hasBackgroundCompletions())) source = "background";
|
|
2942
|
+
if (!source || interruptState.triggered) return;
|
|
2943
|
+
interruptState.triggered = true;
|
|
2944
|
+
interruptState.source = source;
|
|
2945
|
+
ircAbortController.abort();
|
|
2946
|
+
steeringSoftController.abort();
|
|
2943
2947
|
};
|
|
2944
2948
|
|
|
2945
2949
|
const checkSteering = async (): Promise<void> => {
|
|
@@ -2980,7 +2984,7 @@ async function executeToolCalls(
|
|
|
2980
2984
|
}
|
|
2981
2985
|
return;
|
|
2982
2986
|
}
|
|
2983
|
-
await
|
|
2987
|
+
await checkAsideInterrupts();
|
|
2984
2988
|
};
|
|
2985
2989
|
|
|
2986
2990
|
const emitToolResult = (record: (typeof records)[number], result: AgentToolResult<any>, isError: boolean): void => {
|
|
@@ -3283,8 +3287,8 @@ async function executeToolCalls(
|
|
|
3283
3287
|
// and soft-signals cooperative tools (auto-background bash), so the boundary
|
|
3284
3288
|
// dequeue below injects the message promptly. Gated on immediate-interrupt
|
|
3285
3289
|
// mode; checkSteering is idempotent (no-op once triggered).
|
|
3286
|
-
const
|
|
3287
|
-
|
|
3290
|
+
const hasAsidePeek = hasIrcInterrupts !== undefined || hasBackgroundCompletions !== undefined;
|
|
3291
|
+
const watchSteeringWhileRunning = shouldInterruptImmediately && (hasSteeringMessages !== undefined || hasAsidePeek);
|
|
3288
3292
|
const eventDrivenSteeringWatch =
|
|
3289
3293
|
watchSteeringWhileRunning && config.waitForSteeringMessages !== undefined && hasSteeringMessages !== undefined;
|
|
3290
3294
|
const steeringWatchAbortController = new AbortController();
|
|
@@ -3323,13 +3327,13 @@ async function executeToolCalls(
|
|
|
3323
3327
|
}
|
|
3324
3328
|
})()
|
|
3325
3329
|
: undefined;
|
|
3326
|
-
// IRC interrupt records
|
|
3327
|
-
// callback. Keep
|
|
3328
|
-
// system steering uses the event-driven path above and does not poll.
|
|
3330
|
+
// IRC interrupt records and background completions live in session-owned
|
|
3331
|
+
// queues with no wake callback. Keep the timer fallback when either peek is
|
|
3332
|
+
// present; system steering uses the event-driven path above and does not poll.
|
|
3329
3333
|
const steeringWatchTimer =
|
|
3330
|
-
watchSteeringWhileRunning && (!eventDrivenSteeringWatch ||
|
|
3334
|
+
watchSteeringWhileRunning && (!eventDrivenSteeringWatch || hasAsidePeek)
|
|
3331
3335
|
? setInterval(
|
|
3332
|
-
() => void (eventDrivenSteeringWatch ?
|
|
3336
|
+
() => void (eventDrivenSteeringWatch ? checkAsideInterrupts() : checkSteering()),
|
|
3333
3337
|
STEERING_INTERRUPT_POLL_MS,
|
|
3334
3338
|
)
|
|
3335
3339
|
: undefined;
|
|
@@ -3538,8 +3542,11 @@ function createToolSignalAbortedResult(signal: AbortSignal): AgentToolResult<unk
|
|
|
3538
3542
|
};
|
|
3539
3543
|
}
|
|
3540
3544
|
|
|
3545
|
+
/** Origin of a mid-batch interrupt: queued steering, a peer IRC, or a background completion notice. */
|
|
3546
|
+
type AsideInterruptSource = SteeringInterruptSource | "irc" | "background";
|
|
3547
|
+
|
|
3541
3548
|
function createSkippedToolResult(
|
|
3542
|
-
source:
|
|
3549
|
+
source: AsideInterruptSource | undefined,
|
|
3543
3550
|
executionStarted: boolean,
|
|
3544
3551
|
): AgentToolResult<SyntheticToolResultDetails | InterruptedToolResultDetails> {
|
|
3545
3552
|
let reason = "pending steering message";
|
|
@@ -3556,6 +3563,9 @@ function createSkippedToolResult(
|
|
|
3556
3563
|
} else if (source === "irc") {
|
|
3557
3564
|
reason = "pending peer interrupt";
|
|
3558
3565
|
blocker = "interrupt";
|
|
3566
|
+
} else if (source === "background") {
|
|
3567
|
+
reason = "a queued background completion (job or supervised process)";
|
|
3568
|
+
blocker = "completion notice";
|
|
3559
3569
|
}
|
|
3560
3570
|
return {
|
|
3561
3571
|
content: [
|
package/src/agent.ts
CHANGED
|
@@ -486,6 +486,11 @@ export class Agent {
|
|
|
486
486
|
* Hook that peeks whether interrupting IRC asides are queued for the next boundary.
|
|
487
487
|
*/
|
|
488
488
|
hasIrcInterrupts?: AgentLoopConfig["hasIrcInterrupts"];
|
|
489
|
+
/**
|
|
490
|
+
* Hook that peeks whether background completions (jobs, supervised processes)
|
|
491
|
+
* are queued for the next boundary.
|
|
492
|
+
*/
|
|
493
|
+
hasBackgroundCompletions?: AgentLoopConfig["hasBackgroundCompletions"];
|
|
489
494
|
|
|
490
495
|
constructor(opts: AgentOptions = {}) {
|
|
491
496
|
this.#state = { ...this.#state, ...opts.initialState };
|
|
@@ -1660,6 +1665,7 @@ export class Agent {
|
|
|
1660
1665
|
},
|
|
1661
1666
|
waitForSteeringMessages: signal => this.#waitForSteeringMessages(signal),
|
|
1662
1667
|
hasIrcInterrupts: this.hasIrcInterrupts,
|
|
1668
|
+
hasBackgroundCompletions: this.hasBackgroundCompletions,
|
|
1663
1669
|
getFollowUpMessages: signal => this.#dequeueFollowUpMessagesAfterHooks(signal ?? loopSignal),
|
|
1664
1670
|
getAsideMessages: async () => (await this.#asideMessageProvider?.()) ?? [],
|
|
1665
1671
|
onBeforeYield: () => this.#onBeforeYield?.(),
|
|
@@ -24,7 +24,7 @@ import type {
|
|
|
24
24
|
Usage,
|
|
25
25
|
} from "@oh-my-pi/pi-ai";
|
|
26
26
|
import * as AIError from "@oh-my-pi/pi-ai/error";
|
|
27
|
-
import { supportsAnthropicCompaction } from "@oh-my-pi/pi-ai/providers/anthropic";
|
|
27
|
+
import { supportsAnthropicCompaction } from "@oh-my-pi/pi-ai/providers/anthropic-compaction";
|
|
28
28
|
import { isRecord, prompt } from "@oh-my-pi/pi-utils";
|
|
29
29
|
import { type InstrumentedChatSpanOptions, instrumentedCompleteSimple } from "../telemetry";
|
|
30
30
|
import anthropicCompactionInstructionsPrompt from "./prompts/anthropic-compaction-instructions.md" with { type: "text" };
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
import type { Api, CodexCompactionContext, FetchImpl, Model, ProviderSessionState } from "@oh-my-pi/pi-ai";
|
|
11
11
|
import * as AIError from "@oh-my-pi/pi-ai/error";
|
|
12
|
+
import { createOpenAICodexCompactionRequestContext } from "@oh-my-pi/pi-ai/providers/openai-codex-compaction";
|
|
12
13
|
import { applyCodexResponsesLiteShape } from "@oh-my-pi/pi-ai/providers/openai-codex/request-transformer";
|
|
13
14
|
import {
|
|
14
|
-
createOpenAICodexCompactionRequestContext,
|
|
15
15
|
createOpenAICodexCompatibilityMetadata,
|
|
16
|
+
openCodexCompactionEventStream,
|
|
16
17
|
type OpenAICodexCompactionBody,
|
|
17
18
|
type OpenAICodexCompatibilityMetadata,
|
|
18
|
-
openCodexCompactionEventStream,
|
|
19
19
|
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
20
20
|
import {
|
|
21
21
|
getOpenAIPromptCacheKey,
|
|
@@ -25,9 +25,9 @@ import {
|
|
|
25
25
|
} from "@oh-my-pi/pi-ai";
|
|
26
26
|
import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
|
|
27
27
|
import * as AIError from "@oh-my-pi/pi-ai/error";
|
|
28
|
+
import { createOpenAICodexCompactionRequestContext } from "@oh-my-pi/pi-ai/providers/openai-codex-compaction";
|
|
28
29
|
import {
|
|
29
30
|
buildTransformedCodexRequestBody,
|
|
30
|
-
createOpenAICodexCompactionRequestContext,
|
|
31
31
|
type OpenAICodexCompactionBody,
|
|
32
32
|
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
33
33
|
import type { InputItem as CodexInputItem } from "@oh-my-pi/pi-ai/providers/openai-codex/request-transformer";
|
package/src/compaction/openai.ts
CHANGED
|
@@ -16,12 +16,10 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { ProviderHttpError } from "@oh-my-pi/pi-ai/error";
|
|
19
|
+
import { getCodexAttestationHeader } from "@oh-my-pi/pi-ai/providers/openai-codex-attestation";
|
|
20
|
+
import { createOpenAICodexCompactionRequestContext } from "@oh-my-pi/pi-ai/providers/openai-codex-compaction";
|
|
19
21
|
import { applyCodexResponsesLiteShape } from "@oh-my-pi/pi-ai/providers/openai-codex/request-transformer";
|
|
20
|
-
import {
|
|
21
|
-
createOpenAICodexCompactionRequestContext,
|
|
22
|
-
createOpenAICodexCompatibilityMetadata,
|
|
23
|
-
getCodexAttestationHeader,
|
|
24
|
-
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
22
|
+
import { createOpenAICodexCompatibilityMetadata } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
25
23
|
import {
|
|
26
24
|
encodeResponsesToolResultOutput,
|
|
27
25
|
hoistInterleavedResponsesToolBatchMessages,
|
package/src/types.ts
CHANGED
|
@@ -293,6 +293,16 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
293
293
|
* The host owns message injection at the next boundary.
|
|
294
294
|
*/
|
|
295
295
|
hasIrcInterrupts?: () => boolean | Promise<boolean>;
|
|
296
|
+
/**
|
|
297
|
+
* Peeks whether a background completion (finished job, exited supervised
|
|
298
|
+
* process) is queued for aside injection at the next boundary.
|
|
299
|
+
*
|
|
300
|
+
* Same rules as {@link hasIrcInterrupts}: non-consuming, only cuts
|
|
301
|
+
* *interruptible* waits short, ignored when interruptMode is "wait". Without
|
|
302
|
+
* it a completion notice sits behind an hour-long `hub wait` that the agent
|
|
303
|
+
* would have abandoned had it seen the notice.
|
|
304
|
+
*/
|
|
305
|
+
hasBackgroundCompletions?: () => boolean | Promise<boolean>;
|
|
296
306
|
|
|
297
307
|
/**
|
|
298
308
|
* Returns follow-up messages to process after the agent would otherwise stop.
|