@oh-my-pi/pi-ai 10.6.2 → 11.0.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/package.json +2 -2
- package/src/cli.ts +0 -1
- package/src/index.ts +0 -2
- package/src/providers/amazon-bedrock.ts +2 -1
- package/src/providers/azure-openai-responses.ts +9 -7
- package/src/providers/cursor.ts +5 -4
- package/src/providers/google-vertex.ts +3 -2
- package/src/providers/openai-codex-responses.ts +2 -2
- package/src/providers/openai-completions.ts +3 -2
- package/src/providers/openai-responses.ts +4 -7
- package/src/storage.ts +2 -1
- package/src/stream.ts +18 -78
- package/src/usage/kimi.ts +2 -1
- package/src/utils/oauth/google-gemini-cli.ts +3 -1
- package/src/utils/oauth/kimi.ts +3 -3
- package/src/utils/migrate-env.ts +0 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-ai",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@connectrpc/connect-node": "^2.1.1",
|
|
64
64
|
"@google/genai": "^1.39.0",
|
|
65
65
|
"@mistralai/mistralai": "^1.13.0",
|
|
66
|
-
"@oh-my-pi/pi-utils": "
|
|
66
|
+
"@oh-my-pi/pi-utils": "11.0.0",
|
|
67
67
|
"@sinclair/typebox": "^0.34.48",
|
|
68
68
|
"@smithy/node-http-handler": "^4.4.9",
|
|
69
69
|
"ajv": "^8.17.1",
|
package/src/cli.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { createInterface } from "readline";
|
|
3
3
|
import { CliAuthStorage } from "./storage";
|
|
4
|
-
import "./utils/migrate-env";
|
|
5
4
|
import { getOAuthProviders } from "./utils/oauth";
|
|
6
5
|
import { loginAnthropic } from "./utils/oauth/anthropic";
|
|
7
6
|
import { loginCursor } from "./utils/oauth/cursor";
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type ToolConfiguration,
|
|
19
19
|
ToolResultStatus,
|
|
20
20
|
} from "@aws-sdk/client-bedrock-runtime";
|
|
21
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
21
22
|
import { calculateCost } from "../models";
|
|
22
23
|
import type {
|
|
23
24
|
Api,
|
|
@@ -97,7 +98,7 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
97
98
|
|
|
98
99
|
// in Node.js/Bun environment only
|
|
99
100
|
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
100
|
-
config.region = config.region ||
|
|
101
|
+
config.region = config.region || $env.AWS_REGION || $env.AWS_DEFAULT_REGION;
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
config.region = config.region || "us-east-1";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type OpenAI from "openai";
|
|
2
3
|
import { AzureOpenAI } from "openai";
|
|
3
4
|
import type {
|
|
@@ -54,8 +55,8 @@ function resolveDeploymentName(model: Model<"azure-openai-responses">, options?:
|
|
|
54
55
|
if (options?.azureDeploymentName) {
|
|
55
56
|
return options.azureDeploymentName;
|
|
56
57
|
}
|
|
57
|
-
const mappedDeployment = parseDeploymentNameMap(
|
|
58
|
-
return mappedDeployment
|
|
58
|
+
const mappedDeployment = parseDeploymentNameMap($env.AZURE_OPENAI_DEPLOYMENT_NAME_MAP).get(model.id);
|
|
59
|
+
return mappedDeployment ?? model.id;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
// Azure OpenAI Responses-specific options
|
|
@@ -373,10 +374,10 @@ function resolveAzureConfig(
|
|
|
373
374
|
model: Model<"azure-openai-responses">,
|
|
374
375
|
options?: AzureOpenAIResponsesOptions,
|
|
375
376
|
): { baseUrl: string; apiVersion: string } {
|
|
376
|
-
const apiVersion = options?.azureApiVersion ||
|
|
377
|
+
const apiVersion = options?.azureApiVersion || $env.AZURE_OPENAI_API_VERSION || DEFAULT_AZURE_API_VERSION;
|
|
377
378
|
|
|
378
|
-
const baseUrl = options?.azureBaseUrl?.trim() ||
|
|
379
|
-
const resourceName = options?.azureResourceName ||
|
|
379
|
+
const baseUrl = options?.azureBaseUrl?.trim() || $env.AZURE_OPENAI_BASE_URL?.trim() || undefined;
|
|
380
|
+
const resourceName = options?.azureResourceName || $env.AZURE_OPENAI_RESOURCE_NAME;
|
|
380
381
|
|
|
381
382
|
let resolvedBaseUrl = baseUrl;
|
|
382
383
|
|
|
@@ -402,12 +403,13 @@ function resolveAzureConfig(
|
|
|
402
403
|
|
|
403
404
|
function createClient(model: Model<"azure-openai-responses">, apiKey: string, options?: AzureOpenAIResponsesOptions) {
|
|
404
405
|
if (!apiKey) {
|
|
405
|
-
|
|
406
|
+
const envKey = $env.AZURE_OPENAI_API_KEY;
|
|
407
|
+
if (!envKey) {
|
|
406
408
|
throw new Error(
|
|
407
409
|
"Azure OpenAI API key is required. Set AZURE_OPENAI_API_KEY environment variable or pass it as an argument.",
|
|
408
410
|
);
|
|
409
411
|
}
|
|
410
|
-
apiKey =
|
|
412
|
+
apiKey = envKey;
|
|
411
413
|
}
|
|
412
414
|
|
|
413
415
|
const headers = { ...(model.headers ?? {}) };
|
package/src/providers/cursor.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from "node:fs/promises";
|
|
|
3
3
|
import http2 from "node:http2";
|
|
4
4
|
import { create, fromBinary, fromJson, type JsonValue, toBinary, toJson } from "@bufbuild/protobuf";
|
|
5
5
|
import { ValueSchema } from "@bufbuild/protobuf/wkt";
|
|
6
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
6
7
|
import { calculateCost } from "../models";
|
|
7
8
|
import type {
|
|
8
9
|
Api,
|
|
@@ -138,7 +139,7 @@ interface CursorLogEntry {
|
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
async function appendCursorDebugLog(entry: CursorLogEntry): Promise<void> {
|
|
141
|
-
const logPath =
|
|
142
|
+
const logPath = $env.DEBUG_CURSOR_LOG;
|
|
142
143
|
if (!logPath) return;
|
|
143
144
|
try {
|
|
144
145
|
await fs.appendFile(logPath, `${JSON.stringify(entry, debugReplacer)}\n`);
|
|
@@ -148,10 +149,10 @@ async function appendCursorDebugLog(entry: CursorLogEntry): Promise<void> {
|
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
function log(type: string, subtype?: string, data?: unknown): void {
|
|
151
|
-
if (
|
|
152
|
+
if (!$env.DEBUG_CURSOR) return;
|
|
152
153
|
const normalizedData = data ? decodeLogData(data) : data;
|
|
153
154
|
const entry: CursorLogEntry = { ts: Date.now(), type, subtype, data: normalizedData };
|
|
154
|
-
const verbose =
|
|
155
|
+
const verbose = $env.DEBUG_CURSOR === "2" || $env.DEBUG_CURSOR === "verbose";
|
|
155
156
|
const dataStr = verbose && normalizedData ? ` ${JSON.stringify(normalizedData, debugReplacer)?.slice(0, 500)}` : "";
|
|
156
157
|
console.error(`[CURSOR] ${type}${subtype ? `: ${subtype}` : ""}${dataStr}`);
|
|
157
158
|
void appendCursorDebugLog(entry);
|
|
@@ -2065,7 +2066,7 @@ function buildGrpcRequest(
|
|
|
2065
2066
|
|
|
2066
2067
|
const toolNames = context.tools?.map(tool => tool.name) ?? [];
|
|
2067
2068
|
const detail =
|
|
2068
|
-
|
|
2069
|
+
$env.DEBUG_CURSOR === "2"
|
|
2069
2070
|
? ` ${JSON.stringify(clientMessage.message.value, debugReplacer, 2)?.slice(0, 2000)}`
|
|
2070
2071
|
: "";
|
|
2071
2072
|
log("info", "builtRunRequest", {
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type ThinkingConfig,
|
|
6
6
|
ThinkingLevel,
|
|
7
7
|
} from "@google/genai";
|
|
8
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
8
9
|
import { calculateCost } from "../models";
|
|
9
10
|
import type {
|
|
10
11
|
Api,
|
|
@@ -304,7 +305,7 @@ function createClient(model: Model<"google-vertex">, project: string, location:
|
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
function resolveProject(options?: GoogleVertexOptions): string {
|
|
307
|
-
const project = options?.project ||
|
|
308
|
+
const project = options?.project || $env.GOOGLE_CLOUD_PROJECT || $env.GCLOUD_PROJECT;
|
|
308
309
|
if (!project) {
|
|
309
310
|
throw new Error(
|
|
310
311
|
"Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or pass project in options.",
|
|
@@ -314,7 +315,7 @@ function resolveProject(options?: GoogleVertexOptions): string {
|
|
|
314
315
|
}
|
|
315
316
|
|
|
316
317
|
function resolveLocation(options?: GoogleVertexOptions): string {
|
|
317
|
-
const location = options?.location ||
|
|
318
|
+
const location = options?.location || $env.GOOGLE_CLOUD_LOCATION;
|
|
318
319
|
if (!location) {
|
|
319
320
|
throw new Error("Vertex AI requires a location. Set GOOGLE_CLOUD_LOCATION or pass location in options.");
|
|
320
321
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as os from "node:os";
|
|
2
|
-
import { abortableSleep } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { $env, abortableSleep } from "@oh-my-pi/pi-utils";
|
|
3
3
|
import type {
|
|
4
4
|
ResponseFunctionToolCall,
|
|
5
5
|
ResponseInput,
|
|
@@ -71,7 +71,7 @@ export function buildCodexSystemPrompt(args: { userSystemPrompt?: string }): Cod
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
const CODEX_DEBUG =
|
|
74
|
+
const CODEX_DEBUG = $env.PI_CODEX_DEBUG === "1" || $env.PI_CODEX_DEBUG === "true";
|
|
75
75
|
const CODEX_MAX_RETRIES = 2;
|
|
76
76
|
const CODEX_RETRYABLE_STATUS = new Set([408, 429, 500, 502, 503, 504]);
|
|
77
77
|
const CODEX_RETRY_DELAY_MS = 500;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import OpenAI from "openai";
|
|
2
3
|
import type {
|
|
3
4
|
ChatCompletionAssistantMessageParam,
|
|
@@ -348,12 +349,12 @@ async function createClient(
|
|
|
348
349
|
extraHeaders?: Record<string, string>,
|
|
349
350
|
) {
|
|
350
351
|
if (!apiKey) {
|
|
351
|
-
if (
|
|
352
|
+
if (!$env.OPENAI_API_KEY) {
|
|
352
353
|
throw new Error(
|
|
353
354
|
"OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it as an argument.",
|
|
354
355
|
);
|
|
355
356
|
}
|
|
356
|
-
apiKey =
|
|
357
|
+
apiKey = $env.OPENAI_API_KEY;
|
|
357
358
|
}
|
|
358
359
|
|
|
359
360
|
let headers = { ...(model.headers ?? {}), ...(extraHeaders ?? {}) };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import OpenAI from "openai";
|
|
2
3
|
import type {
|
|
3
4
|
Tool as OpenAITool,
|
|
@@ -39,11 +40,7 @@ import { transformMessages } from "./transform-messages";
|
|
|
39
40
|
* Returns '24h' for long retention, undefined for default (in-memory).
|
|
40
41
|
*/
|
|
41
42
|
function getPromptCacheRetention(baseUrl: string): "24h" | undefined {
|
|
42
|
-
if (
|
|
43
|
-
typeof process !== "undefined" &&
|
|
44
|
-
process.env.PI_CACHE_RETENTION === "long" &&
|
|
45
|
-
baseUrl.includes("api.openai.com")
|
|
46
|
-
) {
|
|
43
|
+
if ($env.PI_CACHE_RETENTION === "long" && baseUrl.includes("api.openai.com")) {
|
|
47
44
|
return "24h";
|
|
48
45
|
}
|
|
49
46
|
return undefined;
|
|
@@ -360,12 +357,12 @@ function createClient(
|
|
|
360
357
|
extraHeaders?: Record<string, string>,
|
|
361
358
|
) {
|
|
362
359
|
if (!apiKey) {
|
|
363
|
-
if (
|
|
360
|
+
if (!$env.OPENAI_API_KEY) {
|
|
364
361
|
throw new Error(
|
|
365
362
|
"OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it as an argument.",
|
|
366
363
|
);
|
|
367
364
|
}
|
|
368
|
-
apiKey =
|
|
365
|
+
apiKey = $env.OPENAI_API_KEY;
|
|
369
366
|
}
|
|
370
367
|
|
|
371
368
|
const headers = { ...(model.headers ?? {}), ...(extraHeaders ?? {}) };
|
package/src/storage.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Database } from "bun:sqlite";
|
|
|
7
7
|
import * as fs from "node:fs/promises";
|
|
8
8
|
import * as os from "node:os";
|
|
9
9
|
import * as path from "node:path";
|
|
10
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
10
11
|
import type { OAuthCredentials } from "./utils/oauth/types";
|
|
11
12
|
|
|
12
13
|
type AuthCredential = { type: "api_key"; key: string } | ({ type: "oauth" } & OAuthCredentials);
|
|
@@ -24,7 +25,7 @@ type AuthRow = {
|
|
|
24
25
|
* Get the agent config directory (e.g., ~/.omp/agent/)
|
|
25
26
|
*/
|
|
26
27
|
function getAgentDir(): string {
|
|
27
|
-
const configDir =
|
|
28
|
+
const configDir = $env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".omp", "agent");
|
|
28
29
|
return configDir;
|
|
29
30
|
}
|
|
30
31
|
|
package/src/stream.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
4
5
|
import { supportsXhigh } from "./models";
|
|
5
6
|
import { type BedrockOptions, streamBedrock } from "./providers/amazon-bedrock";
|
|
6
7
|
import { type AnthropicOptions, streamAnthropic } from "./providers/anthropic";
|
|
@@ -32,69 +33,9 @@ import type {
|
|
|
32
33
|
|
|
33
34
|
let cachedVertexAdcCredentialsExists: boolean | null = null;
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
let cachedEnvMap: Record<string, string> | null = null;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Parses a .env file synchronously and extracts key-value pairs.
|
|
40
|
-
*/
|
|
41
|
-
function parseEnvFile(filePath: string): Record<string, string> {
|
|
42
|
-
const result: Record<string, string> = {};
|
|
43
|
-
try {
|
|
44
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
45
|
-
for (const line of content.split("\n")) {
|
|
46
|
-
const trimmed = line.trim();
|
|
47
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
48
|
-
|
|
49
|
-
const eqIndex = trimmed.indexOf("=");
|
|
50
|
-
if (eqIndex === -1) continue;
|
|
51
|
-
|
|
52
|
-
const key = trimmed.slice(0, eqIndex).trim();
|
|
53
|
-
let value = trimmed.slice(eqIndex + 1).trim();
|
|
54
|
-
|
|
55
|
-
// Remove surrounding quotes
|
|
56
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
57
|
-
value = value.slice(1, -1);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
result[key] = value;
|
|
61
|
-
}
|
|
62
|
-
} catch {
|
|
63
|
-
// File doesn't exist or can't be read - return empty
|
|
64
|
-
}
|
|
65
|
-
return result;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function getEnvMap(): Record<string, string> {
|
|
69
|
-
if (cachedEnvMap) return cachedEnvMap;
|
|
70
|
-
|
|
71
|
-
const pruneEmpty = (env: any) =>
|
|
72
|
-
Object.fromEntries(
|
|
73
|
-
Object.entries(env).filter(([k, v]) => typeof k === "string" && typeof v === "string" && v) as [
|
|
74
|
-
string,
|
|
75
|
-
string,
|
|
76
|
-
][],
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
cachedEnvMap = {
|
|
80
|
-
...pruneEmpty(parseEnvFile(path.join(os.homedir(), ".env"))),
|
|
81
|
-
...pruneEmpty(parseEnvFile(path.join(process.cwd(), ".env"))),
|
|
82
|
-
...pruneEmpty(process.env),
|
|
83
|
-
};
|
|
84
|
-
return cachedEnvMap;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Gets an environment variable from process.env or .env files.
|
|
89
|
-
* Checks: process.env → cwd/.env → ~/.env
|
|
90
|
-
*/
|
|
91
|
-
export function getEnv(key: string): string | undefined {
|
|
92
|
-
return getEnvMap()[key];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function hasVertexAdcCredentials(env: Record<string, string>): boolean {
|
|
36
|
+
function hasVertexAdcCredentials(): boolean {
|
|
96
37
|
if (cachedVertexAdcCredentialsExists === null) {
|
|
97
|
-
const gacPath = env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
38
|
+
const gacPath = $env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
98
39
|
if (gacPath) {
|
|
99
40
|
cachedVertexAdcCredentialsExists = fs.existsSync(gacPath);
|
|
100
41
|
} else {
|
|
@@ -106,7 +47,7 @@ function hasVertexAdcCredentials(env: Record<string, string>): boolean {
|
|
|
106
47
|
return cachedVertexAdcCredentialsExists;
|
|
107
48
|
}
|
|
108
49
|
|
|
109
|
-
type KeyResolver = string | ((
|
|
50
|
+
type KeyResolver = string | (() => string | undefined);
|
|
110
51
|
|
|
111
52
|
const serviceProviderMap: Record<string, KeyResolver> = {
|
|
112
53
|
openai: "OPENAI_API_KEY",
|
|
@@ -125,15 +66,15 @@ const serviceProviderMap: Record<string, KeyResolver> = {
|
|
|
125
66
|
exa: "EXA_API_KEY",
|
|
126
67
|
perplexity: "PERPLEXITY_API_KEY",
|
|
127
68
|
// GitHub Copilot uses GitHub personal access token
|
|
128
|
-
"github-copilot":
|
|
69
|
+
"github-copilot": () => $env.COPILOT_GITHUB_TOKEN || $env.GH_TOKEN || $env.GITHUB_TOKEN,
|
|
129
70
|
// ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY
|
|
130
|
-
anthropic:
|
|
71
|
+
anthropic: () => $env.ANTHROPIC_OAUTH_TOKEN || $env.ANTHROPIC_API_KEY,
|
|
131
72
|
// Vertex AI uses Application Default Credentials, not API keys.
|
|
132
73
|
// Auth is configured via `gcloud auth application-default login`.
|
|
133
|
-
"google-vertex":
|
|
134
|
-
const hasCredentials = hasVertexAdcCredentials(
|
|
135
|
-
const hasProject = !!(env.GOOGLE_CLOUD_PROJECT || env.GCLOUD_PROJECT);
|
|
136
|
-
const hasLocation =
|
|
74
|
+
"google-vertex": () => {
|
|
75
|
+
const hasCredentials = hasVertexAdcCredentials();
|
|
76
|
+
const hasProject = !!($env.GOOGLE_CLOUD_PROJECT || $env.GCLOUD_PROJECT);
|
|
77
|
+
const hasLocation = !!$env.GOOGLE_CLOUD_LOCATION;
|
|
137
78
|
if (hasCredentials && hasProject && hasLocation) {
|
|
138
79
|
return "<authenticated>";
|
|
139
80
|
}
|
|
@@ -144,14 +85,14 @@ const serviceProviderMap: Record<string, KeyResolver> = {
|
|
|
144
85
|
// 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock API keys (bearer token)
|
|
145
86
|
// 4. AWS_CONTAINER_CREDENTIALS_* - ECS/Task IAM role credentials
|
|
146
87
|
// 5. AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN - IRSA (EKS) web identity
|
|
147
|
-
"amazon-bedrock":
|
|
88
|
+
"amazon-bedrock": () => {
|
|
148
89
|
const hasEcsCredentials =
|
|
149
|
-
|
|
150
|
-
const hasWebIdentity =
|
|
90
|
+
!!$env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || !!$env.AWS_CONTAINER_CREDENTIALS_FULL_URI;
|
|
91
|
+
const hasWebIdentity = !!$env.AWS_WEB_IDENTITY_TOKEN_FILE && !!$env.AWS_ROLE_ARN;
|
|
151
92
|
if (
|
|
152
|
-
env.AWS_PROFILE ||
|
|
153
|
-
(env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY) ||
|
|
154
|
-
env.AWS_BEARER_TOKEN_BEDROCK ||
|
|
93
|
+
$env.AWS_PROFILE ||
|
|
94
|
+
($env.AWS_ACCESS_KEY_ID && $env.AWS_SECRET_ACCESS_KEY) ||
|
|
95
|
+
$env.AWS_BEARER_TOKEN_BEDROCK ||
|
|
155
96
|
hasEcsCredentials ||
|
|
156
97
|
hasWebIdentity
|
|
157
98
|
) {
|
|
@@ -167,12 +108,11 @@ const serviceProviderMap: Record<string, KeyResolver> = {
|
|
|
167
108
|
* Checks process.env, then cwd/.env, then ~/.env.
|
|
168
109
|
*/
|
|
169
110
|
export function getEnvApiKey(provider: string): string | undefined {
|
|
170
|
-
const env = getEnvMap();
|
|
171
111
|
const resolver = serviceProviderMap[provider];
|
|
172
112
|
if (typeof resolver === "string") {
|
|
173
|
-
return env[resolver];
|
|
113
|
+
return $env[resolver];
|
|
174
114
|
}
|
|
175
|
-
return resolver?.(
|
|
115
|
+
return resolver?.();
|
|
176
116
|
}
|
|
177
117
|
|
|
178
118
|
export function stream<TApi extends Api>(
|
package/src/usage/kimi.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type {
|
|
2
3
|
UsageAmount,
|
|
3
4
|
UsageCache,
|
|
@@ -45,7 +46,7 @@ const toNumber = (value: unknown): number | undefined => {
|
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
function normalizeBaseUrl(baseUrl?: string): string {
|
|
48
|
-
const envBase =
|
|
49
|
+
const envBase = $env.KIMI_CODE_BASE_URL?.trim();
|
|
49
50
|
const candidate = baseUrl?.trim() || envBase || DEFAULT_BASE_URL;
|
|
50
51
|
return candidate.replace(/\/+$/, "");
|
|
51
52
|
}
|
|
@@ -2,6 +2,8 @@
|
|
|
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
|
+
import { $env } from "@oh-my-pi/pi-utils";
|
|
5
7
|
import { OAuthCallbackFlow } from "./callback-server";
|
|
6
8
|
import { generatePKCE } from "./pkce";
|
|
7
9
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
@@ -91,7 +93,7 @@ async function pollOperation(
|
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
async function discoverProject(accessToken: string, onProgress?: (message: string) => void): Promise<string> {
|
|
94
|
-
const envProjectId =
|
|
96
|
+
const envProjectId = $env.GOOGLE_CLOUD_PROJECT || $env.GOOGLE_CLOUD_PROJECT_ID;
|
|
95
97
|
|
|
96
98
|
const headers = {
|
|
97
99
|
Authorization: `Bearer ${accessToken}`,
|
package/src/utils/oauth/kimi.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as crypto from "node:crypto";
|
|
|
6
6
|
import * as fs from "node:fs/promises";
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import { abortableSleep, isEnoent } from "@oh-my-pi/pi-utils";
|
|
9
|
+
import { $env, abortableSleep, isEnoent } from "@oh-my-pi/pi-utils";
|
|
10
10
|
import packageJson from "../../../package.json" with { type: "json" };
|
|
11
11
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
12
12
|
|
|
@@ -37,12 +37,12 @@ interface TokenResponse {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
function getAgentDir(): string {
|
|
40
|
-
const configDir =
|
|
40
|
+
const configDir = $env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".omp", "agent");
|
|
41
41
|
return configDir;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
function resolveOAuthHost(): string {
|
|
45
|
-
return
|
|
45
|
+
return $env.KIMI_CODE_OAUTH_HOST || $env.KIMI_OAUTH_HOST || DEFAULT_OAUTH_HOST;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
function formatDeviceModel(system: string, release: string, arch: string): string {
|
package/src/utils/migrate-env.ts
DELETED