@oh-my-pi/pi-agent-core 18.12.0 → 18.12.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 +10 -0
- package/package.json +8 -8
- package/src/prompts/dsml-tool-call-leak.md +1 -1
- package/src/tokenizer.ts +18 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.12.2] - 2026-10-18
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- The failed-tool-call correction sent to DeepSeek models now also covers chat-template tool-call tokens written out as text, not only malformed DSML ([#16216](https://github.com/can1357/oh-my-pi/pull/16216) by [@H4vC](https://github.com/H4vC))
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed Ollama chat history estimates counting stripped native thinking and missing foreign thinking replayed as text, which skewed compaction after model switches ([#16164](https://github.com/can1357/oh-my-pi/issues/16164))
|
|
14
|
+
|
|
5
15
|
## [18.12.0] - 2026-10-17
|
|
6
16
|
|
|
7
17
|
### Fixed
|
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.12.
|
|
4
|
+
"version": "18.12.2",
|
|
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.12.
|
|
42
|
-
"@oh-my-pi/pi-catalog": "18.12.
|
|
43
|
-
"@oh-my-pi/pi-natives": "18.12.
|
|
44
|
-
"@oh-my-pi/pi-utils": "18.12.
|
|
45
|
-
"@oh-my-pi/pi-wire": "18.12.
|
|
46
|
-
"@oh-my-pi/snapcompact": "18.12.
|
|
41
|
+
"@oh-my-pi/pi-ai": "18.12.2",
|
|
42
|
+
"@oh-my-pi/pi-catalog": "18.12.2",
|
|
43
|
+
"@oh-my-pi/pi-natives": "18.12.2",
|
|
44
|
+
"@oh-my-pi/pi-utils": "18.12.2",
|
|
45
|
+
"@oh-my-pi/pi-wire": "18.12.2",
|
|
46
|
+
"@oh-my-pi/snapcompact": "18.12.2",
|
|
47
47
|
"@opentelemetry/api": "^1.9.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@oh-my-pi/omptype": "18.12.
|
|
50
|
+
"@oh-my-pi/omptype": "18.12.2",
|
|
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"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Tool call failed: your previous response tried to invoke a tool, but the
|
|
1
|
+
Tool call failed: your previous response tried to invoke a tool, but the tool-call markup was malformed, so it arrived as plain text, no tool was executed, and the broken markup was removed from your response. Usually the opening `<|DSML|tool_calls>` and/or `<|DSML|invoke name="…">` tags are missing, the tool name was written as a plain line, or the chat template's tool-call special tokens were typed out as text.
|
|
2
2
|
|
|
3
3
|
A tool call must be one complete envelope:
|
|
4
4
|
|
package/src/tokenizer.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import { renderDemotedThinking } from "@oh-my-pi/pi-ai/dialect/demotion";
|
|
3
|
+
import { ollamaChatDropsOwnThinking } from "@oh-my-pi/pi-ai/providers/ollama";
|
|
2
4
|
import { isColdReplayableResponsesTurn } from "@oh-my-pi/pi-ai/providers/openai-shared";
|
|
3
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
isSameModelTurn,
|
|
7
|
+
shouldDropTruncatedThinkingOnlyAssistant,
|
|
8
|
+
} from "@oh-my-pi/pi-ai/providers/transform-messages";
|
|
4
9
|
import {
|
|
5
10
|
getOpenAIResponsesHistoryItems,
|
|
6
11
|
sanitizeOpenAIResponsesAssistantHistoryItemsForReplay,
|
|
@@ -207,6 +212,7 @@ export class Tokenizer {
|
|
|
207
212
|
readonly #frameBilling: snapcompact.FrameBilling;
|
|
208
213
|
readonly frameBillingKey: string;
|
|
209
214
|
readonly #reasoningReader: ReasoningReplayReader | undefined;
|
|
215
|
+
readonly #dropsOllamaThinking: boolean;
|
|
210
216
|
/** Claude's own API and prefix-bound hosts keep another model's signature from their deployment. */
|
|
211
217
|
readonly #readsDeploymentSignatures: boolean;
|
|
212
218
|
readonly reasoningReplayKey: string;
|
|
@@ -244,6 +250,7 @@ export class Tokenizer {
|
|
|
244
250
|
this.#frameBilling = snapcompact.frameBilling(model ?? undefined);
|
|
245
251
|
this.frameBillingKey = snapcompact.frameBillingKey(this.#frameBilling);
|
|
246
252
|
this.#reasoningReader = reasoningReplayReader(model);
|
|
253
|
+
this.#dropsOllamaThinking = ollamaChatDropsOwnThinking(model);
|
|
247
254
|
const compat = model?.compat;
|
|
248
255
|
this.#readsDeploymentSignatures =
|
|
249
256
|
model?.api === "anthropic-messages" &&
|
|
@@ -415,6 +422,8 @@ export class Tokenizer {
|
|
|
415
422
|
// reaches the wire then (the payload items replay instead); a turn whose
|
|
416
423
|
// backend reported no reasoning tokens keeps the signature as its price.
|
|
417
424
|
const replayedReasoning = this.#replayedReasoningTokens(message);
|
|
425
|
+
const ollamaReader = this.#reasoningReader?.api === "ollama-chat" ? this.#reasoningReader : undefined;
|
|
426
|
+
const ownOllamaTurn = ollamaReader !== undefined && isSameModelTurn(message, ollamaReader);
|
|
418
427
|
if (typeof replayedReasoning === "number") extra += replayedReasoning;
|
|
419
428
|
const signaturesPriced = this.thinkingReplayTokens === "signature";
|
|
420
429
|
// The replay's signature rule (`transformMessages`): an aborted or
|
|
@@ -441,6 +450,13 @@ export class Tokenizer {
|
|
|
441
450
|
if (block.type === "text") {
|
|
442
451
|
fragments.push(block.text);
|
|
443
452
|
} else if (block.type === "thinking") {
|
|
453
|
+
// `transformMessages` drops another model's empty thinking and demotes the
|
|
454
|
+
// rest to visible text; only the reader's own thinking stays native.
|
|
455
|
+
if (ollamaReader && !ownOllamaTurn) {
|
|
456
|
+
if (block.thinking.trim()) fragments.push(renderDemotedThinking(ollamaReader.id, block.thinking));
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (this.#dropsOllamaThinking && ownOllamaTurn) continue;
|
|
444
460
|
fragments.push(block.thinking);
|
|
445
461
|
// Providers charge for the opaque signature/reasoning payload that
|
|
446
462
|
// rides alongside the thinking text (OpenAI Responses encrypted
|
|
@@ -561,6 +577,7 @@ export class Tokenizer {
|
|
|
561
577
|
snapcompact.frameBillingKey(snapcompact.frameBilling(model ?? undefined)) === this.frameBillingKey &&
|
|
562
578
|
reasoningReplayKey(model) === this.reasoningReplayKey &&
|
|
563
579
|
resolveThinkingReplayTokens(model ?? {}) === this.thinkingReplayTokens &&
|
|
580
|
+
ollamaChatDropsOwnThinking(model) === this.#dropsOllamaThinking &&
|
|
564
581
|
(options?.nativeHistoryReplay ?? true) === this.nativeHistoryReplay
|
|
565
582
|
);
|
|
566
583
|
}
|