@oh-my-pi/pi-agent-core 18.11.1 → 18.11.3
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 +16 -0
- package/dist/types/types.d.ts +8 -1
- package/package.json +8 -8
- package/src/agent-loop.ts +19 -12
- package/src/agent.ts +2 -3
- package/src/compaction/openai.ts +3 -2
- package/src/types.ts +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.11.3] - 2026-10-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `prepareQueuedMessages` receives which queue (`steering` or `followUp`) a batch came from ([#16026](https://github.com/can1357/oh-my-pi/pull/16026))
|
|
10
|
+
|
|
11
|
+
## [18.11.2] - 2026-10-16
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `agent_start` carries `resumedToolCallIds` when a continued run first executes the calls of an unpaired assistant tail
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Cancelling an `ask` after a background job finishes now reports the user cancellation instead of telling the model to retry a skipped tool ([#15985](https://github.com/can1357/oh-my-pi/issues/15985))
|
|
20
|
+
|
|
5
21
|
## [18.11.1] - 2026-10-15
|
|
6
22
|
|
|
7
23
|
### Added
|
package/dist/types/types.d.ts
CHANGED
|
@@ -12,8 +12,10 @@ export interface QueuedMessagePreparation {
|
|
|
12
12
|
/** Append context after the originals; undefined stops this attempt, retaining originals unless explicitly removed. */
|
|
13
13
|
commit(): readonly AgentMessage[] | undefined;
|
|
14
14
|
}
|
|
15
|
+
/** Which agent queue a batch came from: steering amends the running task, follow-ups start the next one. */
|
|
16
|
+
export type QueuedMessageQueue = "steering" | "followUp";
|
|
15
17
|
/** Prepare an exclusively claimed batch. Undefined delivers unchanged; the signal also aborts when the claim is cancelled. */
|
|
16
|
-
export type PrepareQueuedMessages = (messages: readonly AgentMessage[], signal: AbortSignal) => QueuedMessagePreparation | undefined | Promise<QueuedMessagePreparation | undefined>;
|
|
18
|
+
export type PrepareQueuedMessages = (messages: readonly AgentMessage[], signal: AbortSignal, queue: QueuedMessageQueue) => QueuedMessagePreparation | undefined | Promise<QueuedMessagePreparation | undefined>;
|
|
17
19
|
/** Called once an aside has been inserted into the agent's live context. */
|
|
18
20
|
export declare const ASIDE_MESSAGE_COMMIT: unique symbol;
|
|
19
21
|
/** Symbol-keyed handoff for one finalized, tool-owned stream speculation session. */
|
|
@@ -1106,6 +1108,11 @@ export interface AgentContext {
|
|
|
1106
1108
|
*/
|
|
1107
1109
|
export type AgentEvent = {
|
|
1108
1110
|
type: "agent_start";
|
|
1111
|
+
/**
|
|
1112
|
+
* Calls of the unpaired assistant tail a continued run executes before its
|
|
1113
|
+
* first model request. They run without a new assistant `message_end`.
|
|
1114
|
+
*/
|
|
1115
|
+
resumedToolCallIds?: string[];
|
|
1109
1116
|
} | {
|
|
1110
1117
|
type: "agent_end";
|
|
1111
1118
|
messages: AgentMessage[];
|
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.11.
|
|
4
|
+
"version": "18.11.3",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": {
|
|
@@ -38,16 +38,16 @@
|
|
|
38
38
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@oh-my-pi/pi-ai": "18.11.
|
|
42
|
-
"@oh-my-pi/pi-catalog": "18.11.
|
|
43
|
-
"@oh-my-pi/pi-natives": "18.11.
|
|
44
|
-
"@oh-my-pi/pi-utils": "18.11.
|
|
45
|
-
"@oh-my-pi/pi-wire": "18.11.
|
|
46
|
-
"@oh-my-pi/snapcompact": "18.11.
|
|
41
|
+
"@oh-my-pi/pi-ai": "18.11.3",
|
|
42
|
+
"@oh-my-pi/pi-catalog": "18.11.3",
|
|
43
|
+
"@oh-my-pi/pi-natives": "18.11.3",
|
|
44
|
+
"@oh-my-pi/pi-utils": "18.11.3",
|
|
45
|
+
"@oh-my-pi/pi-wire": "18.11.3",
|
|
46
|
+
"@oh-my-pi/snapcompact": "18.11.3",
|
|
47
47
|
"@opentelemetry/api": "^1.9.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@oh-my-pi/omptype": "18.11.
|
|
50
|
+
"@oh-my-pi/omptype": "18.11.3",
|
|
51
51
|
"@opentelemetry/context-async-hooks": "^2.9.0",
|
|
52
52
|
"@opentelemetry/sdk-trace-base": "^2.9.0",
|
|
53
53
|
"@types/bun": "^1.3.14"
|
package/src/agent-loop.ts
CHANGED
|
@@ -700,7 +700,17 @@ export function agentLoopContinue(
|
|
|
700
700
|
const newMessages: AgentMessage[] = [];
|
|
701
701
|
const currentContext: AgentContext = { ...context, messages: [...context.messages] };
|
|
702
702
|
|
|
703
|
-
|
|
703
|
+
const resumeTail = unpairedToolCallTail(currentContext.messages);
|
|
704
|
+
stream.push(
|
|
705
|
+
resumeTail
|
|
706
|
+
? {
|
|
707
|
+
type: "agent_start",
|
|
708
|
+
resumedToolCallIds: resumeTail.content.flatMap(block =>
|
|
709
|
+
block.type === "toolCall" ? [block.id] : [],
|
|
710
|
+
),
|
|
711
|
+
}
|
|
712
|
+
: { type: "agent_start" },
|
|
713
|
+
);
|
|
704
714
|
|
|
705
715
|
await runLoop(currentContext, newMessages, config, signal, stream, streamFn);
|
|
706
716
|
} catch (err) {
|
|
@@ -3642,20 +3652,17 @@ async function executeToolCalls(
|
|
|
3642
3652
|
const interrupted = interruptState.triggered;
|
|
3643
3653
|
const perToolAborted = record.signal.aborted;
|
|
3644
3654
|
const abortedDuringExecution = perToolAborted && isError && !completedToolExecution;
|
|
3645
|
-
if (interrupted && abortedDuringExecution) {
|
|
3646
|
-
//
|
|
3647
|
-
//
|
|
3648
|
-
//
|
|
3655
|
+
if (record.interruptible && interrupted && abortedDuringExecution) {
|
|
3656
|
+
// Queued steering/asides abort only interruptible tools. An external
|
|
3657
|
+
// user abort can also fail a non-interruptible tool (e.g. cancelled
|
|
3658
|
+
// ask); keep its actual error instead of attributing it to the queue.
|
|
3649
3659
|
record.skipped = true;
|
|
3650
3660
|
emitToolResult(record, createSkippedToolResult(interruptState.source, executionStarted), true);
|
|
3651
3661
|
} else {
|
|
3652
|
-
//
|
|
3653
|
-
//
|
|
3654
|
-
//
|
|
3655
|
-
//
|
|
3656
|
-
// false "skipped" that discards work the tool performed (#4752). A peer-IRC interrupt
|
|
3657
|
-
// on the batch leaves non-interruptible tools' signals untouched — their genuine
|
|
3658
|
-
// errors survive here too.
|
|
3662
|
+
// A tool that finished before the interrupt landed (`completedToolExecution`)
|
|
3663
|
+
// keeps its real result even if its signal aborted around completion:
|
|
3664
|
+
// the model must see the work it actually performed (#4752).
|
|
3665
|
+
// Non-interruptible tools also retain errors from external user aborts.
|
|
3659
3666
|
emitToolResult(record, result, isError);
|
|
3660
3667
|
}
|
|
3661
3668
|
|
package/src/agent.ts
CHANGED
|
@@ -60,6 +60,7 @@ import type {
|
|
|
60
60
|
AgentTurnEndContext,
|
|
61
61
|
AsideMessage,
|
|
62
62
|
PrepareQueuedMessages,
|
|
63
|
+
QueuedMessageQueue,
|
|
63
64
|
SpeculativeToolExecutionConfig,
|
|
64
65
|
StreamFn,
|
|
65
66
|
ToolCallContext,
|
|
@@ -385,8 +386,6 @@ interface CursorToolResultEntry {
|
|
|
385
386
|
additionalContext?: string;
|
|
386
387
|
}
|
|
387
388
|
|
|
388
|
-
type QueuedMessageQueue = "steering" | "followUp";
|
|
389
|
-
|
|
390
389
|
interface LiveSteeredEntry {
|
|
391
390
|
message: AgentMessage;
|
|
392
391
|
controller: AbortController | undefined;
|
|
@@ -1009,7 +1008,7 @@ export class Agent {
|
|
|
1009
1008
|
this.#queuedMessageClaims[queue] = claim;
|
|
1010
1009
|
const preparationSignal = AbortSignal.any([signal, claim.controller.signal]);
|
|
1011
1010
|
try {
|
|
1012
|
-
const preparation = await prepare(messages, preparationSignal);
|
|
1011
|
+
const preparation = await prepare(messages, preparationSignal, queue);
|
|
1013
1012
|
signal.throwIfAborted();
|
|
1014
1013
|
if (preparationSignal.aborted || this.#queuedMessageClaims[queue] !== claim) return [];
|
|
1015
1014
|
const additional = preparation?.commit();
|
package/src/compaction/openai.ts
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
getOpenAIResponsesHistoryPayload,
|
|
43
43
|
normalizeResponsesToolCallId,
|
|
44
44
|
stripOpenAIResponsesOutputOnlyStatusesForReplay,
|
|
45
|
+
truncateResponseItemId,
|
|
45
46
|
} from "@oh-my-pi/pi-ai/utils";
|
|
46
47
|
import { captureOpenAIHttpError } from "@oh-my-pi/pi-ai/utils/openai-http";
|
|
47
48
|
import { isBedrockOpenAIUrl } from "@oh-my-pi/pi-catalog/hosts";
|
|
@@ -713,8 +714,8 @@ export function buildOpenAiNativeHistory(
|
|
|
713
714
|
let msgId = parsedSignature?.id;
|
|
714
715
|
if (!msgId) {
|
|
715
716
|
msgId = `msg_${msgIndex}`;
|
|
716
|
-
} else
|
|
717
|
-
msgId =
|
|
717
|
+
} else {
|
|
718
|
+
msgId = truncateResponseItemId(msgId, "msg");
|
|
718
719
|
}
|
|
719
720
|
input.push({
|
|
720
721
|
type: "message",
|
package/src/types.ts
CHANGED
|
@@ -38,10 +38,14 @@ export interface QueuedMessagePreparation {
|
|
|
38
38
|
commit(): readonly AgentMessage[] | undefined;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/** Which agent queue a batch came from: steering amends the running task, follow-ups start the next one. */
|
|
42
|
+
export type QueuedMessageQueue = "steering" | "followUp";
|
|
43
|
+
|
|
41
44
|
/** Prepare an exclusively claimed batch. Undefined delivers unchanged; the signal also aborts when the claim is cancelled. */
|
|
42
45
|
export type PrepareQueuedMessages = (
|
|
43
46
|
messages: readonly AgentMessage[],
|
|
44
47
|
signal: AbortSignal,
|
|
48
|
+
queue: QueuedMessageQueue,
|
|
45
49
|
) => QueuedMessagePreparation | undefined | Promise<QueuedMessagePreparation | undefined>;
|
|
46
50
|
|
|
47
51
|
/** Called once an aside has been inserted into the agent's live context. */
|
|
@@ -1252,7 +1256,14 @@ export interface AgentContext {
|
|
|
1252
1256
|
*/
|
|
1253
1257
|
export type AgentEvent =
|
|
1254
1258
|
// Agent lifecycle
|
|
1255
|
-
| {
|
|
1259
|
+
| {
|
|
1260
|
+
type: "agent_start";
|
|
1261
|
+
/**
|
|
1262
|
+
* Calls of the unpaired assistant tail a continued run executes before its
|
|
1263
|
+
* first model request. They run without a new assistant `message_end`.
|
|
1264
|
+
*/
|
|
1265
|
+
resumedToolCallIds?: string[];
|
|
1266
|
+
}
|
|
1256
1267
|
| {
|
|
1257
1268
|
type: "agent_end";
|
|
1258
1269
|
messages: AgentMessage[];
|