@oh-my-pi/pi-ai 18.2.9 → 18.2.10
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 +4 -0
- package/dist/types/usage/claude-reset.d.ts +8 -3
- package/package.json +6 -6
- package/src/providers/anthropic.ts +19 -10
- package/src/usage/claude-reset.ts +24 -21
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Fixed Claude Opus 5.5 ignoring a mid-session switch to high effort when the session started without an explicit effort; the change is now sent as a cache-preserving per-message effort control ([#12909](https://github.com/can1357/oh-my-pi/pull/12909) by [@h4vc](https://github.com/h4vc)).
|
|
8
|
+
|
|
5
9
|
## [18.2.9] - 2026-09-22
|
|
6
10
|
|
|
7
11
|
### Added
|
|
@@ -25,9 +25,14 @@ export interface ClaudeResetConsumeResult {
|
|
|
25
25
|
raw?: unknown;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* Reuse program blocks when a normal usage response actually
|
|
29
|
-
*
|
|
30
|
-
* the
|
|
28
|
+
* Reuse program blocks when a normal usage response actually evaluated them.
|
|
29
|
+
* Anthropic lists every promo program as a key on the plain `/usage` body and
|
|
30
|
+
* leaves the value `null` until the matching probe query (`?cedar_ember=1`,
|
|
31
|
+
* `?at_wall=1`) asks for an evaluation, so a `null` block is "unknown", never
|
|
32
|
+
* "no resets". Only an object block is an answer; anything else returns `null`
|
|
33
|
+
* so the caller falls through to {@link listClaudeResetCredits}. A lone
|
|
34
|
+
* non-redeemable Cedar block is likewise inconclusive because Juniper requires
|
|
35
|
+
* the separate at-wall read.
|
|
31
36
|
*
|
|
32
37
|
* @internal
|
|
33
38
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-ai",
|
|
3
|
-
"version": "18.2.
|
|
3
|
+
"version": "18.2.10",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -152,11 +152,11 @@
|
|
|
152
152
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
153
153
|
},
|
|
154
154
|
"dependencies": {
|
|
155
|
-
"@oh-my-pi/omptype": "18.2.
|
|
156
|
-
"@oh-my-pi/pi-catalog": "18.2.
|
|
157
|
-
"@oh-my-pi/pi-natives": "18.2.
|
|
158
|
-
"@oh-my-pi/pi-utils": "18.2.
|
|
159
|
-
"@oh-my-pi/pi-wire": "18.2.
|
|
155
|
+
"@oh-my-pi/omptype": "18.2.10",
|
|
156
|
+
"@oh-my-pi/pi-catalog": "18.2.10",
|
|
157
|
+
"@oh-my-pi/pi-natives": "18.2.10",
|
|
158
|
+
"@oh-my-pi/pi-utils": "18.2.10",
|
|
159
|
+
"@oh-my-pi/pi-wire": "18.2.10"
|
|
160
160
|
},
|
|
161
161
|
"devDependencies": {
|
|
162
162
|
"@types/bun": "^1.3.14"
|
|
@@ -466,8 +466,11 @@ type AnthropicControlState = {
|
|
|
466
466
|
stableSystemBlocks: AnthropicSystemBlock[] | undefined;
|
|
467
467
|
systemFingerprint: string | undefined;
|
|
468
468
|
controlTransitions: AnthropicControlTransition[];
|
|
469
|
-
|
|
469
|
+
/** Whether the effort baseline was captured; `undefined` efforts are a valid baseline. */
|
|
470
|
+
effortBaselined: boolean;
|
|
471
|
+
/** Top-level `output_config.effort` of the baseline request; `undefined` = API default. */
|
|
470
472
|
baseEffortWire: AnthropicOutputEffort | undefined;
|
|
473
|
+
/** Effort in force at the conversation tail; `undefined` = API default. */
|
|
471
474
|
currentEffort: AnthropicOutputEffort | undefined;
|
|
472
475
|
};
|
|
473
476
|
|
|
@@ -504,7 +507,7 @@ function createAnthropicControlState(): AnthropicControlState {
|
|
|
504
507
|
stableSystemBlocks: undefined,
|
|
505
508
|
systemFingerprint: undefined,
|
|
506
509
|
controlTransitions: [],
|
|
507
|
-
|
|
510
|
+
effortBaselined: false,
|
|
508
511
|
baseEffortWire: undefined,
|
|
509
512
|
currentEffort: undefined,
|
|
510
513
|
};
|
|
@@ -3999,7 +4002,7 @@ function resetAnthropicControlState(state: AnthropicControlState): void {
|
|
|
3999
4002
|
state.stableSystemBlocks = undefined;
|
|
4000
4003
|
state.systemFingerprint = undefined;
|
|
4001
4004
|
state.controlTransitions = [];
|
|
4002
|
-
state.
|
|
4005
|
+
state.effortBaselined = false;
|
|
4003
4006
|
state.baseEffortWire = undefined;
|
|
4004
4007
|
state.currentEffort = undefined;
|
|
4005
4008
|
}
|
|
@@ -4202,6 +4205,13 @@ function planStableAnthropicTools(
|
|
|
4202
4205
|
* later changes as per-message effort. Anthropic applies a system message's
|
|
4203
4206
|
* `output_config.effort` from the next `user` turn on, so the control is
|
|
4204
4207
|
* anchored before the latest user message to take effect on this response.
|
|
4208
|
+
*
|
|
4209
|
+
* An omitted effort means the API's per-model default (`medium` on Opus 5.5,
|
|
4210
|
+
* `high` elsewhere), so it is tracked as its own state rather than assumed to
|
|
4211
|
+
* be any concrete level: every later explicit level is sent as a control. A
|
|
4212
|
+
* per-message control cannot express "back to the API default", so a request
|
|
4213
|
+
* that drops its effort mid-session keeps the level already in force instead
|
|
4214
|
+
* of rewriting the top-level value and invalidating the cache.
|
|
4205
4215
|
*/
|
|
4206
4216
|
function planStableAnthropicEffort(
|
|
4207
4217
|
current: AnthropicOutputEffort | undefined,
|
|
@@ -4210,18 +4220,17 @@ function planStableAnthropicEffort(
|
|
|
4210
4220
|
enabled: boolean,
|
|
4211
4221
|
): AnthropicOutputEffort | undefined {
|
|
4212
4222
|
if (!state || !enabled) return current;
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
state.baseEffort = effective;
|
|
4223
|
+
if (!state.effortBaselined) {
|
|
4224
|
+
state.effortBaselined = true;
|
|
4216
4225
|
state.baseEffortWire = current;
|
|
4217
|
-
state.currentEffort =
|
|
4226
|
+
state.currentEffort = current;
|
|
4218
4227
|
return current;
|
|
4219
4228
|
}
|
|
4220
|
-
if (state.currentEffort !==
|
|
4229
|
+
if (current !== undefined && state.currentEffort !== current) {
|
|
4221
4230
|
const lastUserIndex = messages.findLastIndex(message => message.role === "user");
|
|
4222
4231
|
const messageCount = lastUserIndex >= 0 ? lastUserIndex : messages.length;
|
|
4223
|
-
recordAnthropicControlTransition(state, messages, messageCount, [],
|
|
4224
|
-
state.currentEffort =
|
|
4232
|
+
recordAnthropicControlTransition(state, messages, messageCount, [], current);
|
|
4233
|
+
state.currentEffort = current;
|
|
4225
4234
|
}
|
|
4226
4235
|
return state.baseEffortWire;
|
|
4227
4236
|
}
|
|
@@ -448,9 +448,14 @@ async function withResolvedOrganization(
|
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
/**
|
|
451
|
-
* Reuse program blocks when a normal usage response actually
|
|
452
|
-
*
|
|
453
|
-
* the
|
|
451
|
+
* Reuse program blocks when a normal usage response actually evaluated them.
|
|
452
|
+
* Anthropic lists every promo program as a key on the plain `/usage` body and
|
|
453
|
+
* leaves the value `null` until the matching probe query (`?cedar_ember=1`,
|
|
454
|
+
* `?at_wall=1`) asks for an evaluation, so a `null` block is "unknown", never
|
|
455
|
+
* "no resets". Only an object block is an answer; anything else returns `null`
|
|
456
|
+
* so the caller falls through to {@link listClaudeResetCredits}. A lone
|
|
457
|
+
* non-redeemable Cedar block is likewise inconclusive because Juniper requires
|
|
458
|
+
* the separate at-wall read.
|
|
454
459
|
*
|
|
455
460
|
* @internal
|
|
456
461
|
*/
|
|
@@ -459,26 +464,24 @@ export function parseClaudeResetCreditsFromUsagePayload(
|
|
|
459
464
|
orgId?: string,
|
|
460
465
|
baseUrl?: string,
|
|
461
466
|
): ClaudeResetCreditList | null {
|
|
462
|
-
if (!isRecord(payload)
|
|
463
|
-
const
|
|
464
|
-
|
|
467
|
+
if (!isRecord(payload)) return null;
|
|
468
|
+
const cedarBlock = payload[CEDAR_PROGRAM];
|
|
469
|
+
const juniperBlock = payload[JUNIPER_PROGRAM];
|
|
465
470
|
const normalizedOrgId = orgId?.trim();
|
|
466
471
|
const safeOrgId = normalizedOrgId && ORGANIZATION_ID.test(normalizedOrgId) ? normalizedOrgId : undefined;
|
|
467
|
-
|
|
468
|
-
if (
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
...(baseUrl ? { baseUrl } : {}),
|
|
481
|
-
};
|
|
472
|
+
let cedarList: ClaudeResetCreditList | undefined;
|
|
473
|
+
if (isRecord(cedarBlock)) {
|
|
474
|
+
const parsedCedar = parseCedarStatus(cedarBlock);
|
|
475
|
+
if (!parsedCedar.ok || !parsedCedar.status) return null;
|
|
476
|
+
cedarList = normalizeCedarList(parsedCedar.status, safeOrgId, baseUrl);
|
|
477
|
+
if (cedarList.availableCount > 0 || cedarList.nextCreditId) return cedarList;
|
|
478
|
+
}
|
|
479
|
+
if (isRecord(juniperBlock)) {
|
|
480
|
+
const parsedJuniper = parseJuniperStatus(juniperBlock);
|
|
481
|
+
if (!parsedJuniper.ok || !parsedJuniper.status) return null;
|
|
482
|
+
return normalizeJuniperList(parsedJuniper.status, safeOrgId, baseUrl);
|
|
483
|
+
}
|
|
484
|
+
return cedarList ?? null;
|
|
482
485
|
}
|
|
483
486
|
|
|
484
487
|
/**
|