@oh-my-pi/pi-ai 13.13.0 → 13.13.2
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
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [13.13.2] - 2026-03-18
|
|
6
|
+
### Changed
|
|
7
|
+
|
|
8
|
+
- Modified tool result handling for aborted assistant messages to preserve existing tool results when already recorded, instead of always replacing them with synthetic 'aborted' results
|
|
9
|
+
|
|
5
10
|
## [13.13.0] - 2026-03-18
|
|
6
11
|
### Changed
|
|
7
12
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-ai",
|
|
4
|
-
"version": "13.13.
|
|
4
|
+
"version": "13.13.2",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@aws-sdk/client-bedrock-runtime": "^3",
|
|
42
42
|
"@bufbuild/protobuf": "^2.11",
|
|
43
43
|
"@google/genai": "^1.43",
|
|
44
|
-
"@oh-my-pi/pi-utils": "13.13.
|
|
44
|
+
"@oh-my-pi/pi-utils": "13.13.2",
|
|
45
45
|
"@sinclair/typebox": "^0.34",
|
|
46
46
|
"@smithy/node-http-handler": "^4.4",
|
|
47
47
|
"ajv": "^8.18",
|
|
@@ -2134,7 +2134,7 @@ function convertMessages(model: Model<"openai-codex-responses">, context: Contex
|
|
|
2134
2134
|
} satisfies ResponseOutputMessage);
|
|
2135
2135
|
continue;
|
|
2136
2136
|
}
|
|
2137
|
-
if (block.type === "toolCall"
|
|
2137
|
+
if (block.type === "toolCall") {
|
|
2138
2138
|
const toolCall = block as ToolCall;
|
|
2139
2139
|
const normalized = normalizeResponsesToolCallId(toolCall.id);
|
|
2140
2140
|
outputItems.push({
|
|
@@ -124,101 +124,105 @@ export function transformMessages<TApi extends Api>(
|
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
// Second pass: insert synthetic empty tool results for orphaned tool calls
|
|
127
|
-
//
|
|
127
|
+
// and preserve aborted/errored tool results when they were already persisted.
|
|
128
128
|
const result: Message[] = [];
|
|
129
129
|
let pendingToolCalls: ToolCall[] = [];
|
|
130
|
-
|
|
130
|
+
let pendingAbortedToolCalls = new Map<string, ToolCall>();
|
|
131
|
+
let pendingAbortedTimestamp: number | undefined;
|
|
132
|
+
// Track tool call status: whether resolved (has result) or aborted (synthetic result injected, skip later real results)
|
|
131
133
|
const toolCallStatus = new Map<string, ToolCallStatus>();
|
|
132
134
|
|
|
135
|
+
const flushPendingToolCalls = (timestamp: number): void => {
|
|
136
|
+
if (pendingToolCalls.length === 0) return;
|
|
137
|
+
for (const tc of pendingToolCalls) {
|
|
138
|
+
if (!toolCallStatus.has(tc.id)) {
|
|
139
|
+
result.push({
|
|
140
|
+
role: "toolResult",
|
|
141
|
+
toolCallId: tc.id,
|
|
142
|
+
toolName: tc.name,
|
|
143
|
+
content: [{ type: "text", text: "No result provided" }],
|
|
144
|
+
isError: true,
|
|
145
|
+
timestamp,
|
|
146
|
+
} as ToolResultMessage);
|
|
147
|
+
toolCallStatus.set(tc.id, ToolCallStatus.Resolved);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
pendingToolCalls = [];
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const flushPendingAbortedToolCalls = (): void => {
|
|
154
|
+
if (pendingAbortedTimestamp === undefined) return;
|
|
155
|
+
for (const tc of pendingAbortedToolCalls.values()) {
|
|
156
|
+
if (!toolCallStatus.has(tc.id)) {
|
|
157
|
+
result.push({
|
|
158
|
+
role: "toolResult",
|
|
159
|
+
toolCallId: tc.id,
|
|
160
|
+
toolName: tc.name,
|
|
161
|
+
content: [{ type: "text", text: "aborted" }],
|
|
162
|
+
isError: true,
|
|
163
|
+
timestamp: pendingAbortedTimestamp,
|
|
164
|
+
} as ToolResultMessage);
|
|
165
|
+
toolCallStatus.set(tc.id, ToolCallStatus.Aborted);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
result.push({
|
|
169
|
+
role: "developer",
|
|
170
|
+
content: turnAbortedGuidance,
|
|
171
|
+
timestamp: pendingAbortedTimestamp + 1,
|
|
172
|
+
} as DeveloperMessage);
|
|
173
|
+
pendingAbortedToolCalls = new Map();
|
|
174
|
+
pendingAbortedTimestamp = undefined;
|
|
175
|
+
};
|
|
176
|
+
|
|
133
177
|
for (let i = 0; i < transformed.length; i++) {
|
|
134
178
|
const msg = transformed[i];
|
|
179
|
+
const messageTimestamp = "timestamp" in msg && typeof msg.timestamp === "number" ? msg.timestamp : Date.now();
|
|
135
180
|
|
|
136
181
|
if (msg.role === "assistant") {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
for (const tc of pendingToolCalls) {
|
|
140
|
-
if (!toolCallStatus.has(tc.id)) {
|
|
141
|
-
result.push({
|
|
142
|
-
role: "toolResult",
|
|
143
|
-
toolCallId: tc.id,
|
|
144
|
-
toolName: tc.name,
|
|
145
|
-
content: [{ type: "text", text: "No result provided" }],
|
|
146
|
-
isError: true,
|
|
147
|
-
timestamp: Date.now(),
|
|
148
|
-
} as ToolResultMessage);
|
|
149
|
-
toolCallStatus.set(tc.id, ToolCallStatus.Resolved);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
pendingToolCalls = [];
|
|
153
|
-
}
|
|
182
|
+
flushPendingToolCalls(messageTimestamp);
|
|
183
|
+
flushPendingAbortedToolCalls();
|
|
154
184
|
|
|
155
|
-
// For errored/aborted assistant messages: keep tool calls intact,
|
|
156
|
-
// inject synthetic "aborted" results, and add guidance marker.
|
|
157
|
-
// This preserves structure so the model knows what was attempted.
|
|
158
185
|
const assistantMsg = msg as AssistantMessage;
|
|
159
186
|
const toolCalls = assistantMsg.content.filter(b => b.type === "toolCall") as ToolCall[];
|
|
160
187
|
|
|
161
188
|
if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
|
|
162
|
-
//
|
|
189
|
+
// Keep the assistant message with tool calls intact. If real tool results follow, preserve them;
|
|
190
|
+
// otherwise synthesize aborted results before the next turn boundary.
|
|
163
191
|
result.push(msg);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
for (const tc of toolCalls) {
|
|
167
|
-
toolCallStatus.set(tc.id, ToolCallStatus.Aborted);
|
|
168
|
-
result.push({
|
|
169
|
-
role: "toolResult",
|
|
170
|
-
toolCallId: tc.id,
|
|
171
|
-
toolName: tc.name,
|
|
172
|
-
content: [{ type: "text", text: "aborted" }],
|
|
173
|
-
isError: true,
|
|
174
|
-
timestamp: assistantMsg.timestamp,
|
|
175
|
-
} as ToolResultMessage);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Inject turn-aborted guidance marker as developer message
|
|
179
|
-
result.push({
|
|
180
|
-
role: "developer",
|
|
181
|
-
content: turnAbortedGuidance,
|
|
182
|
-
timestamp: assistantMsg.timestamp + 1,
|
|
183
|
-
} as DeveloperMessage);
|
|
184
|
-
|
|
192
|
+
pendingAbortedToolCalls = new Map(toolCalls.map(toolCall => [toolCall.id, toolCall] as const));
|
|
193
|
+
pendingAbortedTimestamp = assistantMsg.timestamp;
|
|
185
194
|
continue;
|
|
186
195
|
}
|
|
187
196
|
|
|
188
|
-
// Track tool calls from this normal assistant message
|
|
189
197
|
if (toolCalls.length > 0) {
|
|
190
198
|
pendingToolCalls = toolCalls;
|
|
191
199
|
}
|
|
192
200
|
|
|
193
201
|
result.push(msg);
|
|
194
202
|
} else if (msg.role === "toolResult") {
|
|
195
|
-
|
|
203
|
+
if (pendingAbortedToolCalls.has(msg.toolCallId)) {
|
|
204
|
+
pendingAbortedToolCalls.delete(msg.toolCallId);
|
|
205
|
+
toolCallStatus.set(msg.toolCallId, ToolCallStatus.Resolved);
|
|
206
|
+
result.push(msg);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
|
|
196
210
|
if (toolCallStatus.get(msg.toolCallId) === ToolCallStatus.Aborted) continue;
|
|
197
211
|
toolCallStatus.set(msg.toolCallId, ToolCallStatus.Resolved);
|
|
198
212
|
result.push(msg);
|
|
199
213
|
} else if (msg.role === "user" || msg.role === "developer") {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
for (const tc of pendingToolCalls) {
|
|
203
|
-
if (!toolCallStatus.has(tc.id)) {
|
|
204
|
-
result.push({
|
|
205
|
-
role: "toolResult",
|
|
206
|
-
toolCallId: tc.id,
|
|
207
|
-
toolName: tc.name,
|
|
208
|
-
content: [{ type: "text", text: "No result provided" }],
|
|
209
|
-
isError: true,
|
|
210
|
-
timestamp: Date.now(),
|
|
211
|
-
} as ToolResultMessage);
|
|
212
|
-
toolCallStatus.set(tc.id, ToolCallStatus.Resolved);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
pendingToolCalls = [];
|
|
216
|
-
}
|
|
214
|
+
flushPendingToolCalls(messageTimestamp);
|
|
215
|
+
flushPendingAbortedToolCalls();
|
|
217
216
|
result.push(msg);
|
|
218
217
|
} else {
|
|
218
|
+
flushPendingToolCalls(messageTimestamp);
|
|
219
|
+
flushPendingAbortedToolCalls();
|
|
219
220
|
result.push(msg);
|
|
220
221
|
}
|
|
221
222
|
}
|
|
222
223
|
|
|
224
|
+
flushPendingToolCalls(Date.now());
|
|
225
|
+
flushPendingAbortedToolCalls();
|
|
226
|
+
|
|
223
227
|
return result;
|
|
224
228
|
}
|