@@ -4,6 +4,7 @@
|
||||
|
||||
### Added
|
||||
|
||||
- Added a global `httpProxy` setting that applies as `HTTP_PROXY` and `HTTPS_PROXY` for Pi-managed HTTP clients ([#5790](https://github.com/earendil-works/pi/issues/5790)).
|
||||
- Added `auth.json` API key `env` values so provider-specific environment overrides can be scoped to Pi and propagated to inherited provider configuration ([#5728](https://github.com/earendil-works/pi/issues/5728)).
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -69,6 +69,18 @@ Use `/trust` in interactive mode to save a project trust decision for future ses
|
||||
|
||||
Set `PI_SKIP_VERSION_CHECK=1` to disable the Pi version update check. Use `--offline` or `PI_OFFLINE=1` to disable all startup network operations described here, including update checks, package update checks, and install/update telemetry.
|
||||
|
||||
### Network
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `httpProxy` | string | - | HTTP proxy URL applied as `HTTP_PROXY` and `HTTPS_PROXY`. Global setting only. |
|
||||
|
||||
```json
|
||||
{
|
||||
"httpProxy": "http://127.0.0.1:7890"
|
||||
}
|
||||
```
|
||||
|
||||
### Warnings
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
|
||||
@@ -36,6 +36,13 @@ export function formatHttpIdleTimeoutMs(timeoutMs: number): string {
|
||||
return `${timeoutMs / 1000} sec`;
|
||||
}
|
||||
|
||||
export function applyHttpProxySettings(httpProxy: string | undefined): void {
|
||||
const proxy = httpProxy?.trim();
|
||||
if (!proxy) return;
|
||||
process.env.HTTP_PROXY ??= proxy;
|
||||
process.env.HTTPS_PROXY ??= proxy;
|
||||
}
|
||||
|
||||
export function configureHttpDispatcher(timeoutMs: number = DEFAULT_HTTP_IDLE_TIMEOUT_MS): void {
|
||||
const normalizedTimeoutMs = parseHttpIdleTimeoutMs(timeoutMs);
|
||||
if (normalizedTimeoutMs === undefined) {
|
||||
|
||||
@@ -117,6 +117,7 @@ export interface Settings {
|
||||
markdown?: MarkdownSettings;
|
||||
warnings?: WarningSettings;
|
||||
sessionDir?: string; // Custom session storage directory (same format as --session-dir CLI flag)
|
||||
httpProxy?: string; // Proxy URL applied as HTTP_PROXY and HTTPS_PROXY for Pi-managed HTTP clients
|
||||
httpIdleTimeoutMs?: number; // HTTP header/body idle timeout in milliseconds; 0 disables it
|
||||
websocketConnectTimeoutMs?: number; // WebSocket connect/open handshake timeout in milliseconds; 0 disables it
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import { formatNoModelsAvailableMessage } from "./core/auth-guidance.ts";
|
||||
import { AuthStorage } from "./core/auth-storage.ts";
|
||||
import { exportFromFile } from "./core/export-html/index.ts";
|
||||
import type { ExtensionFactory } from "./core/extensions/types.ts";
|
||||
import { configureHttpDispatcher } from "./core/http-dispatcher.ts";
|
||||
import { applyHttpProxySettings, configureHttpDispatcher } from "./core/http-dispatcher.ts";
|
||||
import type { ModelRegistry } from "./core/model-registry.ts";
|
||||
import { resolveCliModel, resolveModelScope, type ScopedModel } from "./core/model-resolver.ts";
|
||||
import { restoreStdout, takeOverStdout } from "./core/output-guard.ts";
|
||||
@@ -466,6 +466,12 @@ export async function main(args: string[], options?: MainOptions) {
|
||||
cleanupWindowsSelfUpdateQuarantine(getPackageDir());
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
const agentDir = getAgentDir();
|
||||
const bootstrapSettingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: false });
|
||||
applyHttpProxySettings(bootstrapSettingsManager.getGlobalSettings().httpProxy);
|
||||
configureHttpDispatcher();
|
||||
|
||||
if (await handlePackageCommand(args, { extensionFactories: options?.extensionFactories })) {
|
||||
const exitCode = process.exitCode ?? 0;
|
||||
if (process.platform === "win32" && exitCode === 0 && args[0] === "update") {
|
||||
@@ -529,11 +535,9 @@ export async function main(args: string[], options?: MainOptions) {
|
||||
validateSessionIdFlags(parsed);
|
||||
|
||||
// Run migrations (pass cwd for project-local migrations)
|
||||
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());
|
||||
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(cwd);
|
||||
time("runMigrations");
|
||||
|
||||
const cwd = process.cwd();
|
||||
const agentDir = getAgentDir();
|
||||
const startupSettingsManager = SettingsManager.create(cwd, agentDir);
|
||||
reportDiagnostics(collectSettingsDiagnostics(startupSettingsManager, "startup session lookup"));
|
||||
|
||||
@@ -726,6 +730,7 @@ export async function main(args: string[], options?: MainOptions) {
|
||||
time("createAgentSessionRuntime");
|
||||
const { services, session, modelFallbackMessage } = runtime;
|
||||
const { settingsManager, modelRegistry, resourceLoader } = services;
|
||||
applyHttpProxySettings(settingsManager.getGlobalSettings().httpProxy);
|
||||
configureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());
|
||||
|
||||
if (parsed.help) {
|
||||
|
||||
53
packages/coding-agent/test/http-dispatcher.test.ts
Normal file
53
packages/coding-agent/test/http-dispatcher.test.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { applyHttpProxySettings } from "../src/core/http-dispatcher.ts";
|
||||
|
||||
const PROXY_ENV_KEYS = ["HTTP_PROXY", "HTTPS_PROXY"] as const;
|
||||
|
||||
describe("http proxy settings", () => {
|
||||
let savedEnv: Record<(typeof PROXY_ENV_KEYS)[number], string | undefined>;
|
||||
|
||||
beforeEach(() => {
|
||||
savedEnv = Object.fromEntries(PROXY_ENV_KEYS.map((key) => [key, process.env[key]])) as Record<
|
||||
(typeof PROXY_ENV_KEYS)[number],
|
||||
string | undefined
|
||||
>;
|
||||
for (const key of PROXY_ENV_KEYS) {
|
||||
delete process.env[key];
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
for (const key of PROXY_ENV_KEYS) {
|
||||
const value = savedEnv[key];
|
||||
if (value === undefined) {
|
||||
delete process.env[key];
|
||||
} else {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("applies httpProxy to HTTP_PROXY and HTTPS_PROXY", () => {
|
||||
applyHttpProxySettings("http://127.0.0.1:7890");
|
||||
|
||||
expect(process.env.HTTP_PROXY).toBe("http://127.0.0.1:7890");
|
||||
expect(process.env.HTTPS_PROXY).toBe("http://127.0.0.1:7890");
|
||||
});
|
||||
|
||||
it("does not override existing proxy env vars", () => {
|
||||
process.env.HTTP_PROXY = "http://env-http:8080";
|
||||
process.env.HTTPS_PROXY = "http://env-https:8080";
|
||||
|
||||
applyHttpProxySettings("http://settings:7890");
|
||||
|
||||
expect(process.env.HTTP_PROXY).toBe("http://env-http:8080");
|
||||
expect(process.env.HTTPS_PROXY).toBe("http://env-https:8080");
|
||||
});
|
||||
|
||||
it("ignores empty values", () => {
|
||||
applyHttpProxySettings(" ");
|
||||
|
||||
expect(process.env.HTTP_PROXY).toBeUndefined();
|
||||
expect(process.env.HTTPS_PROXY).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user