mirror of
https://github.com/earendil-works/pi.git
synced 2026-06-18 15:54:04 +08:00
feat(coding-agent): add experimental feature flag
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
### Added
|
||||
|
||||
- Added the global `experimentalFeatures` setting and `PI_EXPERIMENTAL` environment override for early feature flags.
|
||||
- Added a `project_trust` extension event so global and CLI extensions can decide or defer project trust during startup and runtime cwd switches.
|
||||
- Added project trust gating for project-local settings, resources, instructions, and packages ([#5332](https://github.com/earendil-works/pi/pull/5332)).
|
||||
- Added the latest prompt cache hit rate to the interactive footer.
|
||||
|
||||
@@ -285,7 +285,7 @@ Use `/settings` to modify common options, or edit JSON files directly:
|
||||
| Location | Scope |
|
||||
|----------|-------|
|
||||
| `~/.pi/agent/settings.json` | Global (all projects) |
|
||||
| `.pi/settings.json` | Project (overrides global) |
|
||||
| `.pi/settings.json` | Project (overrides global, except global-only settings) |
|
||||
|
||||
See [docs/settings.md](docs/settings.md) for all options.
|
||||
|
||||
@@ -662,6 +662,7 @@ pi --thinking high "Solve this complex problem"
|
||||
| `PI_OFFLINE` | Disable startup network operations, including update checks, package update checks, and install/update telemetry |
|
||||
| `PI_SKIP_VERSION_CHECK` | Skip the Pi version update check at startup. This prevents the `pi.dev` latest-version request |
|
||||
| `PI_TELEMETRY` | Override install/update telemetry and provider attribution headers. Use `1`/`true`/`yes` to enable or `0`/`false`/`no` to disable. This does not disable update checks |
|
||||
| `PI_EXPERIMENTAL` | Override `experimentalFeatures` for early features. Use `1`/`true`/`yes` to enable or `0`/`false`/`no` to disable |
|
||||
| `PI_CACHE_RETENTION` | Set to `long` for extended prompt cache (Anthropic: 1h, OpenAI: 24h) |
|
||||
| `VISUAL`, `EDITOR` | External editor for Ctrl+G |
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Settings
|
||||
|
||||
Pi uses JSON settings files with project settings overriding global settings.
|
||||
Pi uses JSON settings files with project settings overriding global settings unless a setting notes otherwise.
|
||||
|
||||
| Location | Scope |
|
||||
|----------|-------|
|
||||
@@ -64,6 +64,16 @@ 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.
|
||||
|
||||
### Experimental Features
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `experimentalFeatures` | boolean | `false` | Enable early features that may change or break |
|
||||
|
||||
`experimentalFeatures` is global-only. Set it in `~/.pi/agent/settings.json`; `.pi/settings.json` is ignored for this setting. It is not shown in `/settings`.
|
||||
|
||||
Set `PI_EXPERIMENTAL=1` (or `true`/`yes`) to enable experimental features for one process. If `PI_EXPERIMENTAL` is set, it overrides `experimentalFeatures`; use `0`, `false`, or `no` to force-disable.
|
||||
|
||||
### Warnings
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
@@ -269,7 +279,7 @@ See [packages.md](packages.md) for package management details.
|
||||
|
||||
## Project Overrides
|
||||
|
||||
Project settings (`.pi/settings.json`) override global settings. Nested objects are merged:
|
||||
Project settings (`.pi/settings.json`) override global settings except for global-only settings such as `experimentalFeatures`. Nested objects are merged:
|
||||
|
||||
```json
|
||||
// ~/.pi/agent/settings.json (global)
|
||||
|
||||
@@ -288,6 +288,7 @@ pi --exclude-tools ask_question
|
||||
| `PI_OFFLINE` | Disable startup network operations, including update checks, package update checks, and install/update telemetry |
|
||||
| `PI_SKIP_VERSION_CHECK` | Skip the Pi version update check at startup. This prevents the `pi.dev` latest-version request |
|
||||
| `PI_TELEMETRY` | Override install/update telemetry and provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no`. This does not disable update checks |
|
||||
| `PI_EXPERIMENTAL` | Override `experimentalFeatures` for early features: `1`/`true`/`yes` or `0`/`false`/`no` |
|
||||
| `PI_CACHE_RETENTION` | Set to `long` for extended prompt cache where supported |
|
||||
| `VISUAL`, `EDITOR` | External editor for Ctrl+G |
|
||||
|
||||
|
||||
@@ -378,6 +378,7 @@ ${chalk.bold("Environment Variables:")}
|
||||
PI_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
|
||||
PI_OFFLINE - Disable startup network operations when set to 1/true/yes
|
||||
PI_TELEMETRY - Override install telemetry when set to 1/true/yes or 0/false/no
|
||||
PI_EXPERIMENTAL - Override early features when set to 1/true/yes or 0/false/no
|
||||
PI_SHARE_VIEWER_URL - Base URL for /share command (default: https://pi.dev/session/)
|
||||
|
||||
${chalk.bold("Built-in Tool Names:")}
|
||||
|
||||
@@ -93,6 +93,7 @@ export interface Settings {
|
||||
npmCommand?: string[]; // Command used for npm package lookup/install operations, argv-style (e.g., ["mise", "exec", "node@20", "--", "npm"])
|
||||
collapseChangelog?: boolean; // Show condensed changelog after update (use /changelog for full)
|
||||
enableInstallTelemetry?: boolean; // default: true - anonymous version/update ping after changelog-detected updates
|
||||
experimentalFeatures?: boolean; // default: false - global-only opt-in for early features; overridden by PI_EXPERIMENTAL
|
||||
packages?: PackageSource[]; // Array of npm/git package sources (string or object with filtering)
|
||||
extensions?: string[]; // Array of local extension file paths or directories
|
||||
skills?: string[]; // Array of local skill file paths or directories
|
||||
@@ -893,6 +894,21 @@ export class SettingsManager {
|
||||
this.save();
|
||||
}
|
||||
|
||||
getExperimentalFeaturesEnabled(): boolean {
|
||||
const envValue = process.env.PI_EXPERIMENTAL;
|
||||
if (envValue !== undefined) {
|
||||
const normalized = envValue.toLowerCase();
|
||||
return envValue === "1" || normalized === "true" || normalized === "yes";
|
||||
}
|
||||
return this.globalSettings.experimentalFeatures === true;
|
||||
}
|
||||
|
||||
setExperimentalFeaturesEnabled(enabled: boolean): void {
|
||||
this.globalSettings.experimentalFeatures = enabled;
|
||||
this.markModified("experimentalFeatures");
|
||||
this.save();
|
||||
}
|
||||
|
||||
getPackages(): PackageSource[] {
|
||||
return [...(this.settings.packages ?? [])];
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ describe("SettingsManager", () => {
|
||||
const testDir = join(process.cwd(), "test-settings-tmp");
|
||||
const agentDir = join(testDir, "agent");
|
||||
const projectDir = join(testDir, "project");
|
||||
const originalPiExperimental = process.env.PI_EXPERIMENTAL;
|
||||
|
||||
beforeEach(() => {
|
||||
delete process.env.PI_EXPERIMENTAL;
|
||||
// Clean up and create fresh directories
|
||||
if (existsSync(testDir)) {
|
||||
rmSync(testDir, { recursive: true });
|
||||
@@ -20,6 +22,11 @@ describe("SettingsManager", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalPiExperimental === undefined) {
|
||||
delete process.env.PI_EXPERIMENTAL;
|
||||
} else {
|
||||
process.env.PI_EXPERIMENTAL = originalPiExperimental;
|
||||
}
|
||||
if (existsSync(testDir)) {
|
||||
rmSync(testDir, { recursive: true });
|
||||
}
|
||||
@@ -252,6 +259,52 @@ describe("SettingsManager", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("experimentalFeatures", () => {
|
||||
it("should default to false", () => {
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
expect(manager.getExperimentalFeaturesEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it("should load the global setting", () => {
|
||||
writeFileSync(join(agentDir, "settings.json"), JSON.stringify({ experimentalFeatures: true }));
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
expect(manager.getExperimentalFeaturesEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
it("should ignore project settings", () => {
|
||||
writeFileSync(join(projectDir, ".pi", "settings.json"), JSON.stringify({ experimentalFeatures: true }));
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
expect(manager.getExperimentalFeaturesEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it("should let PI_EXPERIMENTAL enable experimental features", () => {
|
||||
process.env.PI_EXPERIMENTAL = "1";
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
expect(manager.getExperimentalFeaturesEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
it("should let PI_EXPERIMENTAL override the global setting", () => {
|
||||
process.env.PI_EXPERIMENTAL = "0";
|
||||
writeFileSync(join(agentDir, "settings.json"), JSON.stringify({ experimentalFeatures: true }));
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
|
||||
expect(manager.getExperimentalFeaturesEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it("should save to global settings", async () => {
|
||||
const settingsPath = join(agentDir, "settings.json");
|
||||
const manager = SettingsManager.create(projectDir, agentDir);
|
||||
manager.setExperimentalFeaturesEnabled(true);
|
||||
await manager.flush();
|
||||
|
||||
expect(JSON.parse(readFileSync(settingsPath, "utf-8")).experimentalFeatures).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("project settings directory creation", () => {
|
||||
it("should not create .pi folder when only reading project settings", () => {
|
||||
// Create agent dir with global settings, but NO .pi folder in project
|
||||
|
||||
Reference in New Issue
Block a user