@oh-my-pi/pi-ai 18.2.4 → 18.2.5
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,16 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.2.5] - 2026-09-17
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added support for templating and custom base and authentication URLs in OAuth flows.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed Anthropic prompt-cache breakpoints stalling when conversations include mid-conversation tool changes, preventing growing message tails from being unnecessarily re-billed as uncached input.
|
|
14
|
+
|
|
5
15
|
## [18.2.4] - 2026-09-17
|
|
6
16
|
|
|
7
17
|
### Added
|
|
@@ -48,7 +48,7 @@ export declare function postTokenRequest(request: CompiledOAuthRequest, standard
|
|
|
48
48
|
response: Response;
|
|
49
49
|
}>;
|
|
50
50
|
/** Bearer GET declared by `userinfo`; failures leave identity fields unset. */
|
|
51
|
-
export declare function applyUserinfo(userinfo: CompiledUserinfo | undefined, credentials: OAuthCredentials, context: RequestContext): Promise<OAuthCredentials>;
|
|
51
|
+
export declare function applyUserinfo(userinfo: CompiledUserinfo | undefined, credentials: OAuthCredentials, context: RequestContext, vars?: TemplateVars): Promise<OAuthCredentials>;
|
|
52
52
|
/** Runs the rule's after-exchange / after-refresh hook, if declared. */
|
|
53
53
|
export declare function applyAfterExchange(hook: string | undefined, credentials: OAuthCredentials, context: ExchangeContext): Promise<OAuthCredentials>;
|
|
54
54
|
export declare function describeError(error: unknown): string;
|
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.5",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -128,11 +128,11 @@
|
|
|
128
128
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
129
129
|
},
|
|
130
130
|
"dependencies": {
|
|
131
|
-
"@oh-my-pi/omptype": "18.2.
|
|
132
|
-
"@oh-my-pi/pi-catalog": "18.2.
|
|
133
|
-
"@oh-my-pi/pi-natives": "18.2.
|
|
134
|
-
"@oh-my-pi/pi-utils": "18.2.
|
|
135
|
-
"@oh-my-pi/pi-wire": "18.2.
|
|
131
|
+
"@oh-my-pi/omptype": "18.2.5",
|
|
132
|
+
"@oh-my-pi/pi-catalog": "18.2.5",
|
|
133
|
+
"@oh-my-pi/pi-natives": "18.2.5",
|
|
134
|
+
"@oh-my-pi/pi-utils": "18.2.5",
|
|
135
|
+
"@oh-my-pi/pi-wire": "18.2.5"
|
|
136
136
|
},
|
|
137
137
|
"devDependencies": {
|
|
138
138
|
"@types/bun": "^1.3.14"
|
|
@@ -1563,7 +1563,9 @@ async function* iterateAnthropicEvents(
|
|
|
1563
1563
|
let sawMessageStart = false;
|
|
1564
1564
|
let sawMessageEnd = false;
|
|
1565
1565
|
|
|
1566
|
-
|
|
1566
|
+
// Capture `raw` only when the diagnostic observer exists; otherwise the
|
|
1567
|
+
// per-frame wire-line array is pure token-path garbage.
|
|
1568
|
+
for await (const sse of readSseEvents(response.body, signal, onSseEvent ? { captureRaw: true } : undefined)) {
|
|
1567
1569
|
notifyRawSseEvent(onSseEvent, sse);
|
|
1568
1570
|
if (sse.event === "error") {
|
|
1569
1571
|
throw createAnthropicSseStreamError(sse.data);
|
|
@@ -3978,11 +3980,26 @@ function applyPromptCaching(params: MessageCreateParamsStreaming, cacheControl?:
|
|
|
3978
3980
|
// Stable historical decimation checkpoint every 15 user turns (15th, 30th, 45th...)
|
|
3979
3981
|
const decimationIndices = userIndices.filter((_, ordinal) => (ordinal + 1) % ANTHROPIC_DECIMATION_INTERVAL === 0);
|
|
3980
3982
|
|
|
3981
|
-
// Collect up to 2 trailing candidates from the reusable prefix
|
|
3983
|
+
// Collect up to 2 trailing candidates from the reusable prefix, skipping
|
|
3984
|
+
// mid-conversation tool-control messages. They contain only tool_addition /
|
|
3985
|
+
// tool_removal blocks, so cache_control is always rejected there; parking
|
|
3986
|
+
// the rolling window on one spends the tail breakpoint on a decoration
|
|
3987
|
+
// that always fails, and with decimation checkpoints present the remaining
|
|
3988
|
+
// breakpoints land on already-cached history while the growing tail is
|
|
3989
|
+
// re-billed as uncached input every turn.
|
|
3982
3990
|
const trailingCandidates: number[] = [];
|
|
3983
3991
|
for (let index = stableMessageEnd; index >= 0 && trailingCandidates.length < 2; index--) {
|
|
3984
3992
|
const message = params.messages[index];
|
|
3985
3993
|
if (!message) continue;
|
|
3994
|
+
if (
|
|
3995
|
+
message.role === "system" &&
|
|
3996
|
+
typeof message.content !== "string" &&
|
|
3997
|
+
Array.isArray(message.content) &&
|
|
3998
|
+
message.content.length > 0 &&
|
|
3999
|
+
message.content.every(block => block.type === "tool_addition" || block.type === "tool_removal")
|
|
4000
|
+
) {
|
|
4001
|
+
continue;
|
|
4002
|
+
}
|
|
3986
4003
|
trailingCandidates.push(index);
|
|
3987
4004
|
}
|
|
3988
4005
|
|
|
@@ -267,10 +267,11 @@ export async function applyUserinfo(
|
|
|
267
267
|
userinfo: CompiledUserinfo | undefined,
|
|
268
268
|
credentials: OAuthCredentials,
|
|
269
269
|
context: RequestContext,
|
|
270
|
+
vars: TemplateVars = {},
|
|
270
271
|
): Promise<OAuthCredentials> {
|
|
271
272
|
if (!userinfo) return credentials;
|
|
272
273
|
try {
|
|
273
|
-
const response = await context.fetch(userinfo.url, {
|
|
274
|
+
const response = await context.fetch(template(userinfo.url, vars), {
|
|
274
275
|
headers: { ...context.headers, Authorization: `Bearer ${credentials.access}` },
|
|
275
276
|
signal: context.signal,
|
|
276
277
|
});
|
|
@@ -93,6 +93,8 @@ export class DeclarativeOAuthCodeFlow extends OAuthCallbackFlow {
|
|
|
93
93
|
#verifier = "";
|
|
94
94
|
#clientId?: string;
|
|
95
95
|
#clientSecret?: string;
|
|
96
|
+
#base?: string;
|
|
97
|
+
#auth?: string;
|
|
96
98
|
|
|
97
99
|
constructor(
|
|
98
100
|
ctrl: OAuthController,
|
|
@@ -123,6 +125,8 @@ export class DeclarativeOAuthCodeFlow extends OAuthCallbackFlow {
|
|
|
123
125
|
const signal = this.ctrl.signal;
|
|
124
126
|
this.#clientId = rule.clientId ? await resolveValue(rule.clientId, signal) : undefined;
|
|
125
127
|
this.#clientSecret = rule.clientSecret ? await resolveValue(rule.clientSecret, signal) : undefined;
|
|
128
|
+
this.#base = rule.baseUrl ? (await resolveValue(rule.baseUrl, signal)).replace(/\/+$/, "") : undefined;
|
|
129
|
+
this.#auth = rule.authUrl ? (await resolveValue(rule.authUrl, signal)).replace(/\/+$/, "") : undefined;
|
|
126
130
|
let challenge: string | undefined;
|
|
127
131
|
if (rule.pkce) {
|
|
128
132
|
const pkce = await generatePKCE();
|
|
@@ -136,6 +140,8 @@ export class DeclarativeOAuthCodeFlow extends OAuthCallbackFlow {
|
|
|
136
140
|
scope,
|
|
137
141
|
state,
|
|
138
142
|
code_challenge: challenge,
|
|
143
|
+
base: this.#base,
|
|
144
|
+
auth: this.#auth,
|
|
139
145
|
};
|
|
140
146
|
const params = new URLSearchParams();
|
|
141
147
|
if (rule.standardAuthorizeParams) {
|
|
@@ -150,7 +156,7 @@ export class DeclarativeOAuthCodeFlow extends OAuthCallbackFlow {
|
|
|
150
156
|
if (state) params.set("state", state);
|
|
151
157
|
}
|
|
152
158
|
for (const key in rule.authorizeParams) params.set(key, template(rule.authorizeParams[key], vars));
|
|
153
|
-
const authorizeUrl = await resolveValue(rule.authorizeUrl, signal);
|
|
159
|
+
const authorizeUrl = template(await resolveValue(rule.authorizeUrl, signal), vars);
|
|
154
160
|
return { url: `${authorizeUrl}?${params.toString()}`, instructions: rule.instructions };
|
|
155
161
|
}
|
|
156
162
|
|
|
@@ -185,6 +191,8 @@ export class DeclarativeOAuthCodeFlow extends OAuthCallbackFlow {
|
|
|
185
191
|
code_verifier: rule.pkce ? this.#verifier : undefined,
|
|
186
192
|
client_id: this.#clientId,
|
|
187
193
|
client_secret: this.#clientSecret,
|
|
194
|
+
base: this.#base,
|
|
195
|
+
auth: this.#auth,
|
|
188
196
|
};
|
|
189
197
|
const context = { provider: this.#provider, fetch: this.#fetch, signal };
|
|
190
198
|
const { body } = await postTokenRequest(
|
|
@@ -203,7 +211,7 @@ export class DeclarativeOAuthCodeFlow extends OAuthCallbackFlow {
|
|
|
203
211
|
);
|
|
204
212
|
throwIfCancelled(signal);
|
|
205
213
|
let credentials = mapCredentials(rule.credential, body, this.#provider);
|
|
206
|
-
credentials = await applyUserinfo(rule.userinfo, credentials, context);
|
|
214
|
+
credentials = await applyUserinfo(rule.userinfo, credentials, context, vars);
|
|
207
215
|
throwIfCancelled(signal);
|
|
208
216
|
return applyAfterExchange(rule.afterExchange, credentials, {
|
|
209
217
|
provider: this.#provider,
|
|
@@ -31,7 +31,8 @@ async function loginClient(policy: CompiledAuthProvider, signal?: AbortSignal) {
|
|
|
31
31
|
redirectUri: login.callback.redirectUri
|
|
32
32
|
? await resolveValue(login.callback.redirectUri, signal)
|
|
33
33
|
: `http://${login.callback.hostname}:${login.callback.port}${login.callback.path}`,
|
|
34
|
-
base: undefined,
|
|
34
|
+
base: login.baseUrl ? (await resolveValue(login.baseUrl, signal)).replace(/\/+$/, "") : undefined,
|
|
35
|
+
auth: login.authUrl ? (await resolveValue(login.authUrl, signal)).replace(/\/+$/, "") : undefined,
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
if (login?.kind === "device-code") {
|
|
@@ -40,9 +41,10 @@ async function loginClient(policy: CompiledAuthProvider, signal?: AbortSignal) {
|
|
|
40
41
|
clientSecret: undefined,
|
|
41
42
|
redirectUri: undefined,
|
|
42
43
|
base: login.baseUrl ? await resolveValue(login.baseUrl, signal) : undefined,
|
|
44
|
+
auth: undefined,
|
|
43
45
|
};
|
|
44
46
|
}
|
|
45
|
-
return { clientId: undefined, clientSecret: undefined, redirectUri: undefined, base: undefined };
|
|
47
|
+
return { clientId: undefined, clientSecret: undefined, redirectUri: undefined, base: undefined, auth: undefined };
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
function createRequestRefresh(rule: RequestRefresh, policy: CompiledAuthProvider): Refresher {
|
|
@@ -66,6 +68,7 @@ function createRequestRefresh(rule: RequestRefresh, policy: CompiledAuthProvider
|
|
|
66
68
|
client_secret: client.clientSecret,
|
|
67
69
|
redirect_uri: client.redirectUri,
|
|
68
70
|
base: client.base,
|
|
71
|
+
auth: client.auth,
|
|
69
72
|
claude_code_sdk_version: claudeCodeSdkVersion,
|
|
70
73
|
};
|
|
71
74
|
const { body } = await postTokenRequest(
|