@f5-sales-demo/pi-ai 20.20.6 → 20.22.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,12 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Omit an empty OpenAI-compatible `tools` field unless prior tool-call history requires the explicit empty array, and suppress the internal no-auth credential sentinel from keyless request headers ([#2942](https://github.com/f5-sales-demo/xcsh/issues/2942), [#3361](https://github.com/f5-sales-demo/xcsh/issues/3361)).
|
|
10
|
+
|
|
5
11
|
## [20.3.0] - 2026-08-04
|
|
6
12
|
|
|
7
13
|
### Changed
|
|
@@ -433,7 +439,7 @@
|
|
|
433
439
|
- Removed `UsageCache` and `UsageCacheEntry` interfaces—caching is now handled internally by AuthStorage
|
|
434
440
|
- Removed `google-gemini-cli-usage` export; use new `gemini` usage provider instead
|
|
435
441
|
- Removed `resetInMs` computation from all usage providers
|
|
436
|
-
- Removed cache TTL constants and cache management from usage fetchers (claude,
|
|
442
|
+
- Removed cache TTL constants and cache management from usage fetchers (claude, GitHub Copilot, google-antigravity, kimi, openai-codex, zai)
|
|
437
443
|
|
|
438
444
|
### Fixed
|
|
439
445
|
|
|
@@ -1294,7 +1300,7 @@
|
|
|
1294
1300
|
|
|
1295
1301
|
### Changed
|
|
1296
1302
|
|
|
1297
|
-
- Updated
|
|
1303
|
+
- Updated `@anthropic-ai/sdk` to ^0.72.1
|
|
1298
1304
|
- Updated @aws-sdk/client-bedrock-runtime to ^3.982.0
|
|
1299
1305
|
- Updated @google/genai to ^1.39.0
|
|
1300
1306
|
- Updated @smithy/node-http-handler to ^4.4.9
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/pi-ai",
|
|
4
|
-
"version": "20.
|
|
4
|
+
"version": "20.22.2",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@anthropic-ai/sdk": "^0.115",
|
|
47
47
|
"@aws-sdk/client-bedrock-runtime": "^3",
|
|
48
48
|
"@bufbuild/protobuf": "^2.11",
|
|
49
|
-
"@f5-sales-demo/pi-utils": "20.
|
|
49
|
+
"@f5-sales-demo/pi-utils": "20.22.2",
|
|
50
50
|
"@google/genai": "^2.15",
|
|
51
51
|
"@sinclair/typebox": "^0.34",
|
|
52
52
|
"@smithy/node-http-handler": "^4.4",
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type Message,
|
|
19
19
|
type MessageAttribution,
|
|
20
20
|
type Model,
|
|
21
|
+
NO_AUTH_API_KEY,
|
|
21
22
|
type ServiceTier,
|
|
22
23
|
type StopReason,
|
|
23
24
|
type StreamFunction,
|
|
@@ -581,6 +582,7 @@ async function createClient(
|
|
|
581
582
|
apiKey = $env.OPENAI_API_KEY;
|
|
582
583
|
}
|
|
583
584
|
const rawApiKey = apiKey;
|
|
585
|
+
const omitAuthorization = rawApiKey === NO_AUTH_API_KEY;
|
|
584
586
|
|
|
585
587
|
let headers = { ...(model.headers ?? {}), ...(extraHeaders ?? {}) };
|
|
586
588
|
if (model.provider === "openrouter") {
|
|
@@ -609,7 +611,19 @@ async function createClient(
|
|
|
609
611
|
let capturedErrorResponse: CapturedHttpErrorResponse | undefined;
|
|
610
612
|
const wrappedFetch = Object.assign(
|
|
611
613
|
async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {
|
|
612
|
-
|
|
614
|
+
let fetchInput = input;
|
|
615
|
+
let fetchInit = init;
|
|
616
|
+
if (omitAuthorization) {
|
|
617
|
+
if (input instanceof Request) {
|
|
618
|
+
const headers = new Headers(input.headers);
|
|
619
|
+
headers.delete("Authorization");
|
|
620
|
+
fetchInput = new Request(input, { headers });
|
|
621
|
+
}
|
|
622
|
+
const headers = new Headers(init?.headers);
|
|
623
|
+
headers.delete("Authorization");
|
|
624
|
+
fetchInit = { ...init, headers };
|
|
625
|
+
}
|
|
626
|
+
const response = await fetch(fetchInput, fetchInit);
|
|
613
627
|
if (response.ok) {
|
|
614
628
|
capturedErrorResponse = undefined;
|
|
615
629
|
return response;
|
|
@@ -715,7 +729,7 @@ function buildParams(
|
|
|
715
729
|
params.service_tier = options.serviceTier;
|
|
716
730
|
}
|
|
717
731
|
|
|
718
|
-
if (context.tools) {
|
|
732
|
+
if (context.tools && context.tools.length > 0) {
|
|
719
733
|
const builtTools = convertTools(context.tools, compat, toolStrictModeOverride);
|
|
720
734
|
params.tools = builtTools.tools;
|
|
721
735
|
toolStrictMode = builtTools.toolStrictMode;
|
package/src/types.ts
CHANGED
|
@@ -30,6 +30,9 @@ import type { AssistantMessageEventStream } from "./utils/event-stream";
|
|
|
30
30
|
|
|
31
31
|
export type { AssistantMessageEventStream } from "./utils/event-stream";
|
|
32
32
|
|
|
33
|
+
/** Internal credential sentinel that keeps keyless providers selectable without sending authentication. */
|
|
34
|
+
export const NO_AUTH_API_KEY = "N/A";
|
|
35
|
+
|
|
33
36
|
export type KnownApi =
|
|
34
37
|
| "openai-completions"
|
|
35
38
|
| "openai-responses"
|
|
@@ -19,6 +19,11 @@ const CALLBACK_PATH = "/callback";
|
|
|
19
19
|
|
|
20
20
|
export type CallbackResult = { code: string; state: string };
|
|
21
21
|
|
|
22
|
+
interface CallbackServer {
|
|
23
|
+
port: number;
|
|
24
|
+
stop(closeActiveConnections?: boolean): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
export interface OAuthCallbackFlowOptions {
|
|
23
28
|
preferredPort: number;
|
|
24
29
|
callbackPath?: string;
|
|
@@ -117,13 +122,13 @@ export abstract class OAuthCallbackFlow {
|
|
|
117
122
|
/**
|
|
118
123
|
* Start callback server, trying preferred port first, falling back to random.
|
|
119
124
|
*/
|
|
120
|
-
async #startCallbackServer(expectedState: string): Promise<{ server:
|
|
125
|
+
async #startCallbackServer(expectedState: string): Promise<{ server: CallbackServer; redirectUri: string }> {
|
|
121
126
|
try {
|
|
122
127
|
const server = this.#createServer(this.preferredPort, expectedState);
|
|
123
128
|
if (this.redirectUri) {
|
|
124
129
|
return { server, redirectUri: this.redirectUri };
|
|
125
130
|
}
|
|
126
|
-
const redirectUri = `http://${this.callbackHostname}:${
|
|
131
|
+
const redirectUri = `http://${this.callbackHostname}:${server.port}${this.callbackPath}`;
|
|
127
132
|
return { server, redirectUri };
|
|
128
133
|
} catch {
|
|
129
134
|
if (this.redirectUri) {
|
|
@@ -142,13 +147,45 @@ export abstract class OAuthCallbackFlow {
|
|
|
142
147
|
/**
|
|
143
148
|
* Create HTTP server for OAuth callback.
|
|
144
149
|
*/
|
|
145
|
-
#createServer(port: number, expectedState: string):
|
|
146
|
-
|
|
147
|
-
|
|
150
|
+
#createServer(port: number, expectedState: string): CallbackServer {
|
|
151
|
+
if (this.callbackHostname !== DEFAULT_HOSTNAME) {
|
|
152
|
+
return this.#createSingleServer(this.callbackHostname, port, expectedState);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Bun resolves a localhost listener to IPv6 on some Linux images while clients resolve
|
|
156
|
+
// localhost to IPv4. Bind both loopback addresses, but keep localhost in the redirect URI
|
|
157
|
+
// so OAuth providers receive the conventional, portable callback host.
|
|
158
|
+
const ipv4Server = this.#createSingleServer("127.0.0.1", port, expectedState);
|
|
159
|
+
try {
|
|
160
|
+
const ipv6Server = this.#createSingleServer("::1", ipv4Server.port, expectedState);
|
|
161
|
+
return {
|
|
162
|
+
port: ipv4Server.port,
|
|
163
|
+
stop: closeActiveConnections => {
|
|
164
|
+
ipv4Server.stop(closeActiveConnections);
|
|
165
|
+
ipv6Server.stop(closeActiveConnections);
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
} catch (error) {
|
|
169
|
+
ipv4Server.stop();
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
#createSingleServer(hostname: string, port: number, expectedState: string): CallbackServer {
|
|
175
|
+
const server = Bun.serve({
|
|
176
|
+
hostname,
|
|
148
177
|
port,
|
|
149
178
|
reusePort: false,
|
|
150
179
|
fetch: req => this.#handleCallback(req, expectedState),
|
|
151
180
|
});
|
|
181
|
+
if (server.port === undefined) {
|
|
182
|
+
server.stop();
|
|
183
|
+
throw new Error(`OAuth callback server did not report a bound port for ${hostname}`);
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
port: server.port,
|
|
187
|
+
stop: closeActiveConnections => server.stop(closeActiveConnections),
|
|
188
|
+
};
|
|
152
189
|
}
|
|
153
190
|
|
|
154
191
|
/**
|