@oh-my-pi/pi-ai 8.1.0 → 8.2.0
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/README.md +11 -12
- package/package.json +38 -14
- package/src/cli.ts +6 -6
- package/src/providers/amazon-bedrock.ts +12 -13
- package/src/providers/anthropic.ts +25 -26
- package/src/providers/cursor.ts +57 -57
- package/src/providers/google-gemini-cli-usage.ts +2 -2
- package/src/providers/google-gemini-cli.ts +8 -10
- package/src/providers/google-shared.ts +12 -13
- package/src/providers/google-vertex.ts +7 -7
- package/src/providers/google.ts +8 -8
- package/src/providers/openai-codex/request-transformer.ts +6 -6
- package/src/providers/openai-codex-responses.ts +28 -28
- package/src/providers/openai-completions.ts +39 -39
- package/src/providers/openai-responses.ts +31 -31
- package/src/providers/transform-messages.ts +3 -3
- package/src/storage.ts +29 -19
- package/src/stream.ts +6 -6
- package/src/types.ts +1 -2
- package/src/usage/claude.ts +4 -4
- package/src/usage/github-copilot.ts +3 -4
- package/src/usage/google-antigravity.ts +3 -3
- package/src/usage/openai-codex.ts +4 -4
- package/src/usage/zai.ts +3 -3
- package/src/usage.ts +0 -1
- package/src/utils/event-stream.ts +4 -4
- package/src/utils/oauth/anthropic.ts +0 -1
- package/src/utils/oauth/callback-server.ts +2 -3
- package/src/utils/oauth/github-copilot.ts +2 -3
- package/src/utils/oauth/google-antigravity.ts +0 -1
- package/src/utils/oauth/google-gemini-cli.ts +2 -3
- package/src/utils/oauth/index.ts +11 -12
- package/src/utils/oauth/openai-codex.ts +0 -1
- package/src/utils/overflow.ts +2 -2
- package/src/utils/validation.ts +4 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
|
-
import { CODEX_BASE_URL } from "
|
|
2
|
+
import { CODEX_BASE_URL } from "../providers/openai-codex/constants";
|
|
3
3
|
import type {
|
|
4
4
|
UsageAmount,
|
|
5
5
|
UsageCache,
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
UsageProvider,
|
|
10
10
|
UsageReport,
|
|
11
11
|
UsageWindow,
|
|
12
|
-
} from "
|
|
12
|
+
} from "../usage";
|
|
13
13
|
|
|
14
14
|
const CODEX_USAGE_PATH = "wham/usage";
|
|
15
15
|
const DEFAULT_CACHE_TTL_MS = 60_000;
|
|
@@ -264,9 +264,9 @@ function buildUsageLimit(args: {
|
|
|
264
264
|
function resolveCacheExpiry(args: { report: UsageReport | null; nowMs: number }): number {
|
|
265
265
|
const { report, nowMs } = args;
|
|
266
266
|
if (!report) return nowMs + DEFAULT_CACHE_TTL_MS;
|
|
267
|
-
const exhausted = report.limits.some(
|
|
267
|
+
const exhausted = report.limits.some(limit => limit.status === "exhausted");
|
|
268
268
|
const resetCandidates = report.limits
|
|
269
|
-
.map(
|
|
269
|
+
.map(limit => limit.window?.resetsAt)
|
|
270
270
|
.filter((value): value is number => typeof value === "number" && Number.isFinite(value));
|
|
271
271
|
const earliestReset = resetCandidates.length > 0 ? Math.min(...resetCandidates) : undefined;
|
|
272
272
|
if (exhausted && earliestReset) return earliestReset;
|
package/src/usage/zai.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
UsageReport,
|
|
8
8
|
UsageStatus,
|
|
9
9
|
UsageWindow,
|
|
10
|
-
} from "
|
|
10
|
+
} from "../usage";
|
|
11
11
|
|
|
12
12
|
const DEFAULT_ENDPOINT = "https://api.z.ai";
|
|
13
13
|
const QUOTA_PATH = "/api/monitor/usage/quota/limit";
|
|
@@ -133,7 +133,7 @@ function buildCacheKey(params: UsageFetchParams): string {
|
|
|
133
133
|
|
|
134
134
|
function resolveCacheExpiry(now: number, limits: UsageLimit[]): number {
|
|
135
135
|
const earliestReset = limits
|
|
136
|
-
.map(
|
|
136
|
+
.map(limit => limit.window?.resetsAt)
|
|
137
137
|
.filter((value): value is number => typeof value === "number" && Number.isFinite(value))
|
|
138
138
|
.reduce((min, value) => (min === undefined ? value : Math.min(min, value)), undefined as number | undefined);
|
|
139
139
|
if (!earliestReset) return now + DEFAULT_CACHE_TTL_MS;
|
|
@@ -288,5 +288,5 @@ async function fetchZaiUsage(params: UsageFetchParams, ctx: UsageFetchContext):
|
|
|
288
288
|
export const zaiUsageProvider: UsageProvider = {
|
|
289
289
|
id: "zai",
|
|
290
290
|
fetchUsage: fetchZaiUsage,
|
|
291
|
-
supports:
|
|
291
|
+
supports: params => params.provider === "zai" && params.credential.type === "api_key",
|
|
292
292
|
};
|
package/src/usage.ts
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Provides a normalized schema to represent multiple limit windows, model tiers,
|
|
5
5
|
* and shared quotas across providers.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
7
|
import type { Provider } from "./types";
|
|
9
8
|
|
|
10
9
|
export type UsageUnit = "percent" | "tokens" | "requests" | "usd" | "minutes" | "bytes" | "unknown";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssistantMessage, AssistantMessageEvent } from "
|
|
1
|
+
import type { AssistantMessage, AssistantMessageEvent } from "../types";
|
|
2
2
|
|
|
3
3
|
// Generic event stream class for async iteration
|
|
4
4
|
export class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
@@ -53,7 +53,7 @@ export class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
|
53
53
|
} else if (this.done) {
|
|
54
54
|
return;
|
|
55
55
|
} else {
|
|
56
|
-
const result = await new Promise<IteratorResult<T>>(
|
|
56
|
+
const result = await new Promise<IteratorResult<T>>(resolve => this.waiting.push(resolve));
|
|
57
57
|
if (result.done) return;
|
|
58
58
|
yield result.value;
|
|
59
59
|
}
|
|
@@ -68,8 +68,8 @@ export class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
|
68
68
|
export class AssistantMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
|
|
69
69
|
constructor() {
|
|
70
70
|
super(
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
event => event.type === "done" || event.type === "error",
|
|
72
|
+
event => {
|
|
73
73
|
if (event.type === "done") {
|
|
74
74
|
return event.message;
|
|
75
75
|
} else if (event.type === "error") {
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* - generateAuthUrl(): Build provider-specific authorization URL
|
|
11
11
|
* - exchangeToken(): Exchange authorization code for tokens
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
13
|
import templateHtml from "./oauth.html" with { type: "text" };
|
|
15
14
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
16
15
|
|
|
@@ -63,7 +62,7 @@ export abstract class OAuthCallbackFlow {
|
|
|
63
62
|
const bytes = new Uint8Array(16);
|
|
64
63
|
crypto.getRandomValues(bytes);
|
|
65
64
|
return Array.from(bytes)
|
|
66
|
-
.map(
|
|
65
|
+
.map(value => value.toString(16).padStart(2, "0"))
|
|
67
66
|
.join("");
|
|
68
67
|
}
|
|
69
68
|
|
|
@@ -125,7 +124,7 @@ export abstract class OAuthCallbackFlow {
|
|
|
125
124
|
hostname: DEFAULT_HOSTNAME,
|
|
126
125
|
port,
|
|
127
126
|
reusePort: false,
|
|
128
|
-
fetch:
|
|
127
|
+
fetch: req => this.handleCallback(req, expectedState),
|
|
129
128
|
});
|
|
130
129
|
}
|
|
131
130
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GitHub Copilot OAuth flow
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
import { getModels } from "@oh-my-pi/pi-ai/models";
|
|
6
4
|
import { abortableSleep } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { getModels } from "../../models";
|
|
7
6
|
import type { OAuthCredentials } from "./types";
|
|
8
7
|
|
|
9
8
|
const decode = (s: string) => atob(s);
|
|
@@ -279,7 +278,7 @@ async function enableAllGitHubCopilotModels(
|
|
|
279
278
|
): Promise<void> {
|
|
280
279
|
const models = getModels("github-copilot");
|
|
281
280
|
await Promise.all(
|
|
282
|
-
models.map(async
|
|
281
|
+
models.map(async model => {
|
|
283
282
|
const success = await enableGitHubCopilotModel(token, model.id, enterpriseDomain);
|
|
284
283
|
onProgress?.(model.id, success);
|
|
285
284
|
}),
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Antigravity OAuth flow (Gemini 3, Claude, GPT-OSS via Google Cloud)
|
|
3
3
|
* Uses different OAuth credentials than google-gemini-cli for access to additional models.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
import { OAuthCallbackFlow } from "./callback-server";
|
|
7
6
|
import { generatePKCE } from "./pkce";
|
|
8
7
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Gemini CLI OAuth flow (Google Cloud Code Assist)
|
|
3
3
|
* Standard Gemini models only (gemini-2.0-flash, gemini-2.5-*)
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
5
|
import { OAuthCallbackFlow } from "./callback-server";
|
|
7
6
|
import { generatePKCE } from "./pkce";
|
|
8
7
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
@@ -49,7 +48,7 @@ interface GoogleRpcErrorResponse {
|
|
|
49
48
|
|
|
50
49
|
function getDefaultTier(allowedTiers?: Array<{ id?: string; isDefault?: boolean }>): { id?: string } {
|
|
51
50
|
if (!allowedTiers || allowedTiers.length === 0) return { id: TIER_LEGACY };
|
|
52
|
-
const defaultTier = allowedTiers.find(
|
|
51
|
+
const defaultTier = allowedTiers.find(t => t.isDefault);
|
|
53
52
|
return defaultTier ?? { id: TIER_LEGACY };
|
|
54
53
|
}
|
|
55
54
|
|
|
@@ -58,7 +57,7 @@ function isVpcScAffectedUser(payload: unknown): boolean {
|
|
|
58
57
|
if (!("error" in payload)) return false;
|
|
59
58
|
const error = (payload as GoogleRpcErrorResponse).error;
|
|
60
59
|
if (!error?.details || !Array.isArray(error.details)) return false;
|
|
61
|
-
return error.details.some(
|
|
60
|
+
return error.details.some(detail => detail.reason === "SECURITY_POLICY_VIOLATED");
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
async function pollOperation(
|
package/src/utils/oauth/index.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// High-level API
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { refreshAnthropicToken } from "./anthropic";
|
|
5
|
+
import { refreshCursorToken } from "./cursor";
|
|
6
|
+
import { refreshGitHubCopilotToken } from "./github-copilot";
|
|
7
|
+
import { refreshAntigravityToken } from "./google-antigravity";
|
|
8
|
+
import { refreshGoogleCloudToken } from "./google-gemini-cli";
|
|
9
|
+
import { refreshOpenAICodexToken } from "./openai-codex";
|
|
10
|
+
import type { OAuthCredentials, OAuthProvider, OAuthProviderInfo } from "./types";
|
|
11
|
+
|
|
1
12
|
/**
|
|
2
13
|
* OAuth credential management for AI providers.
|
|
3
14
|
*
|
|
@@ -36,18 +47,6 @@ export { loginOpenAICodex, refreshOpenAICodexToken } from "./openai-codex";
|
|
|
36
47
|
|
|
37
48
|
export * from "./types";
|
|
38
49
|
|
|
39
|
-
// ============================================================================
|
|
40
|
-
// High-level API
|
|
41
|
-
// ============================================================================
|
|
42
|
-
|
|
43
|
-
import { refreshAnthropicToken } from "./anthropic";
|
|
44
|
-
import { refreshCursorToken } from "./cursor";
|
|
45
|
-
import { refreshGitHubCopilotToken } from "./github-copilot";
|
|
46
|
-
import { refreshAntigravityToken } from "./google-antigravity";
|
|
47
|
-
import { refreshGoogleCloudToken } from "./google-gemini-cli";
|
|
48
|
-
import { refreshOpenAICodexToken } from "./openai-codex";
|
|
49
|
-
import type { OAuthCredentials, OAuthProvider, OAuthProviderInfo } from "./types";
|
|
50
|
-
|
|
51
50
|
/**
|
|
52
51
|
* Refresh token for any OAuth provider.
|
|
53
52
|
* Saves the new credentials and returns the new access token.
|
package/src/utils/overflow.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssistantMessage } from "
|
|
1
|
+
import type { AssistantMessage } from "../types";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Regex patterns to detect context overflow errors from different providers.
|
|
@@ -85,7 +85,7 @@ export function isContextOverflow(message: AssistantMessage, contextWindow?: num
|
|
|
85
85
|
// Case 1: Check error message patterns
|
|
86
86
|
if (message.stopReason === "error" && message.errorMessage) {
|
|
87
87
|
// Check known patterns
|
|
88
|
-
if (OVERFLOW_PATTERNS.some(
|
|
88
|
+
if (OVERFLOW_PATTERNS.some(p => p.test(message.errorMessage!))) {
|
|
89
89
|
return true;
|
|
90
90
|
}
|
|
91
91
|
|
package/src/utils/validation.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import AjvModule from "ajv";
|
|
2
2
|
import addFormatsModule from "ajv-formats";
|
|
3
|
+
import type { Tool, ToolCall } from "../types";
|
|
3
4
|
|
|
4
5
|
// Handle both default and named exports (ESM/CJS interop)
|
|
5
6
|
const Ajv = (AjvModule as any).default || AjvModule;
|
|
6
7
|
const addFormats = (addFormatsModule as any).default || addFormatsModule;
|
|
7
8
|
|
|
8
|
-
import type { Tool, ToolCall } from "@oh-my-pi/pi-ai/types";
|
|
9
|
-
|
|
10
9
|
// ============================================================================
|
|
11
10
|
// Type Coercion Utilities
|
|
12
11
|
// ============================================================================
|
|
@@ -50,7 +49,7 @@ function normalizeExpectedTypes(typeParam: unknown): string[] {
|
|
|
50
49
|
* Used to verify that a parsed JSON value is actually what the schema wants.
|
|
51
50
|
*/
|
|
52
51
|
function matchesExpectedType(value: unknown, expectedTypes: string[]): boolean {
|
|
53
|
-
return expectedTypes.some(
|
|
52
|
+
return expectedTypes.some(type => {
|
|
54
53
|
switch (type) {
|
|
55
54
|
case "string":
|
|
56
55
|
return typeof value === "string";
|
|
@@ -157,7 +156,7 @@ function decodeJsonPointer(pointer: string): string[] {
|
|
|
157
156
|
return pointer
|
|
158
157
|
.split("/")
|
|
159
158
|
.slice(1) // Remove leading empty segment from initial "/"
|
|
160
|
-
.map(
|
|
159
|
+
.map(segment => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
/**
|
|
@@ -310,7 +309,7 @@ if (!isBrowserExtension) {
|
|
|
310
309
|
* @throws Error if tool is not found or validation fails
|
|
311
310
|
*/
|
|
312
311
|
export function validateToolCall(tools: Tool[], toolCall: ToolCall): any {
|
|
313
|
-
const tool = tools.find(
|
|
312
|
+
const tool = tools.find(t => t.name === toolCall.name);
|
|
314
313
|
if (!tool) {
|
|
315
314
|
throw new Error(`Tool "${toolCall.name}" not found`);
|
|
316
315
|
}
|