fix(config): respect configured model

This commit is contained in:
Ivan Pereira
2026-05-11 15:16:42 +01:00
parent 18e38ac89a
commit 4e77f38d5d
8 changed files with 137 additions and 20 deletions
+11
View File
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.2.1] - 2026-05-11
### Changed
- Model selection is now controlled by `/perplexity-config` or `PI_PERPLEXITY_MODEL` instead of an LLM-facing tool parameter.
- Updated the configured model list with current Perplexity internal model slugs.
### Added
- Opt-in live E2E test for validating Perplexity model selection.
## [0.2.0] - 2026-03-21
### Added
+9 -1
View File
@@ -56,9 +56,10 @@ Once installed, the agent automatically calls `perplexity_search` whenever it ne
| `query` | string | ✅ | The search query |
| `recency` | string | — | Filter by age: `hour` · `day` · `week` · `month` · `year` |
| `limit` | number | — | Max sources to include (150) |
| `model` | string | — | Model preference, e.g. `pplx_pro_upgraded`, `pplx_pro`, `experimental`, `gpt54`, `gpt54_thinking`, `claude46sonnet`, `claude46sonnetthinking`, `gemini31pro_high`, `nv_nemotron_3_super`, `pplx_reasoning`, `pplx_alpha` |
| `incognito` | boolean | — | Whether to hide the search from Perplexity history; defaults to `true` |
Model selection is configured globally with `/perplexity-config` or `PI_PERPLEXITY_MODEL`; it is not exposed as a tool parameter, so agent-generated tool calls cannot accidentally override your configured model.
### Output format
The tool returns structured text the agent can reason over:
@@ -98,6 +99,13 @@ bun test # Run tests
bunx tsc --noEmit # Type check
```
Optional live model-selection E2E test (requires cached auth from `/perplexity-login`):
```bash
PI_PERPLEXITY_E2E=1 bun test test/e2e-models.test.ts
PI_PERPLEXITY_E2E=1 PI_PERPLEXITY_E2E_MODELS=pplx_pro_upgraded,gpt54 bun test test/e2e-models.test.ts
```
## License
MIT — see [LICENSE](LICENSE) for details.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "pi-perplexity",
"version": "0.2.0",
"version": "0.2.1",
"description": "Perplexity web search for pi — uses your Pro/Max subscription, no API credits needed",
"keywords": [
"pi-package",
+1 -14
View File
@@ -6,20 +6,7 @@ import {
saveConfig as defaultSaveConfig,
type PerplexityConfig,
} from "../config.js";
const KNOWN_MODELS: { value: string; label: string }[] = [
{ value: "pplx_pro_upgraded", label: "Best (auto)" },
{ value: "pplx_pro", label: "Default Pro" },
{ value: "experimental", label: "Sonar" },
{ value: "gpt54", label: "GPT-5.4" },
{ value: "gpt54_thinking", label: "GPT-5.4 Thinking" },
{ value: "claude46sonnet", label: "Claude 4.6 Sonnet" },
{ value: "claude46sonnetthinking", label: "Claude 4.6 Sonnet Thinking" },
{ value: "gemini31pro_high", label: "Gemini 3.1 Pro" },
{ value: "nv_nemotron_3_super", label: "Nemotron 3 Super" },
{ value: "pplx_reasoning", label: "Default Reasoning" },
{ value: "pplx_alpha", label: "Deep Research" },
];
import { KNOWN_MODELS } from "../search/models.js";
function formatCurrentConfig(config: { model?: string; incognito?: boolean }): string {
const model = config.model ?? "pplx_pro_upgraded (default)";
-2
View File
@@ -32,7 +32,6 @@ export default function (pi: ExtensionAPI) {
limit: Type.Optional(
Type.Number({ description: "Max sources to return", minimum: 1, maximum: 50 }),
),
model: Type.Optional(Type.String({ description: "Model preference" })),
incognito: Type.Optional(Type.Boolean({ description: "Hide search from Perplexity history" })),
}),
renderCall: renderPerplexityCall,
@@ -76,7 +75,6 @@ export default function (pi: ExtensionAPI) {
const config = await loadConfig();
const { model, incognito } = resolveSearchDefaults(
{
...(params.model !== undefined ? { model: params.model } : {}),
...(params.incognito !== undefined ? { incognito: params.incognito } : {}),
},
config,
+36
View File
@@ -0,0 +1,36 @@
export interface ModelOption {
value: string;
label: string;
}
export const KNOWN_MODELS: ModelOption[] = [
{ value: "pplx_pro_upgraded", label: "Pro (auto)" },
{ value: "pplx_pro", label: "Best (auto)" },
{ value: "experimental", label: "Sonar" },
{ value: "pplx_reasoning", label: "Reasoning" },
{ value: "pplx_alpha", label: "Deep Research" },
{ value: "gpt54", label: "GPT-5.4" },
{ value: "gpt54_thinking", label: "GPT-5.4 Thinking" },
{ value: "gpt52", label: "GPT-5.2" },
{ value: "gpt52_thinking", label: "GPT-5.2 Thinking" },
{ value: "gpt52_pro", label: "GPT-5.2 Pro" },
{ value: "gpt51", label: "GPT-5.1" },
{ value: "gpt51_thinking", label: "GPT-5.1 Thinking" },
{ value: "claude46sonnet", label: "Claude 4.6 Sonnet" },
{ value: "claude46sonnetthinking", label: "Claude 4.6 Sonnet Thinking" },
{ value: "claude47opus", label: "Claude 4.7 Opus" },
{ value: "claude47opusthinking", label: "Claude 4.7 Opus Thinking" },
{ value: "claude45sonnet", label: "Claude 4.5 Sonnet" },
{ value: "claude45sonnetthinking", label: "Claude 4.5 Sonnet Thinking" },
{ value: "gemini31pro_low", label: "Gemini 3.1 Pro" },
{ value: "gemini31pro_high", label: "Gemini 3.1 Pro Thinking" },
{ value: "gemini30pro", label: "Gemini 3 Pro" },
{ value: "gemini30flash", label: "Gemini 3 Flash" },
{ value: "gemini30flash_high", label: "Gemini 3 Flash Thinking" },
{ value: "grok41nonreasoning", label: "Grok 4.1" },
{ value: "grok41reasoning", label: "Grok 4.1 Reasoning" },
{ value: "grok4nonthinking", label: "Grok 4" },
{ value: "grok4", label: "Grok 4 Thinking" },
{ value: "nv_nemotron_3_super", label: "Nemotron 3 Super" },
{ value: "kimik25thinking", label: "Kimi K2.5 Thinking" },
];
+68
View File
@@ -0,0 +1,68 @@
import { describe, expect, test } from "bun:test";
import { loadToken } from "../src/auth/storage.js";
import { searchPerplexity } from "../src/search/client.js";
const DEFAULT_MODELS = [
"pplx_pro_upgraded",
"experimental",
"pplx_reasoning",
"gpt54",
"claude46sonnetthinking",
];
const runE2E = process.env.PI_PERPLEXITY_E2E === "1";
const maybeTest = runE2E ? test : test.skip;
function configuredModels(): string[] {
const raw = process.env.PI_PERPLEXITY_E2E_MODELS;
if (!raw) return DEFAULT_MODELS;
return raw
.split(",")
.map((model) => model.trim())
.filter(Boolean);
}
function configuredDelayMs(): number {
const raw = Number(process.env.PI_PERPLEXITY_E2E_DELAY_MS ?? "1500");
return Number.isFinite(raw) && raw >= 0 ? raw : 1500;
}
async function delay(ms: number): Promise<void> {
await new Promise((resolve) => setTimeout(resolve, ms));
}
describe("Perplexity model selection e2e", () => {
maybeTest(
"sends requested model slugs and receives matching display_model values",
async () => {
const token = await loadToken();
if (!token) {
throw new Error("No cached Perplexity token. Run /perplexity-login before PI_PERPLEXITY_E2E=1 bun test.");
}
const models = configuredModels();
const delayMs = configuredDelayMs();
for (const model of models) {
const result = await searchPerplexity(
{
query: "Say exactly OK",
model,
incognito: true,
limit: 1,
},
token.access,
);
expect(result.answer.trim().startsWith("OK")).toBe(true);
expect(result.displayModel).toBe(model);
if (delayMs > 0 && model !== models.at(-1)) {
await delay(delayMs);
}
}
},
{ timeout: 180_000 },
);
});
+11 -2
View File
@@ -28,19 +28,28 @@ describe("perplexity_search execute", () => {
const { default: registerExtension } = await import(`../src/index.ts?test=${crypto.randomUUID()}`);
let execute: ((toolCallId: string, params: any, signal?: AbortSignal, onUpdate?: any, ctx?: any) => Promise<any>) | undefined;
let parameters: unknown;
registerExtension({
registerCommand() {
return undefined;
},
registerTool(tool: { execute: typeof execute }) {
registerTool(tool: { execute: typeof execute; parameters: unknown }) {
execute = tool.execute;
parameters = tool.parameters;
},
} as any);
expect(execute).toBeDefined();
expect(JSON.stringify(parameters)).not.toContain("model");
const result = await execute!("tool-1", { query: "how many planets" }, undefined, undefined, { ui: {} });
const result = await execute!(
"tool-1",
{ query: "how many planets", model: "pplx_pro" },
undefined,
undefined,
{ ui: {} },
);
expect(loadConfig).toHaveBeenCalledTimes(1);
expect(resolveSearchDefaults).toHaveBeenCalledWith({}, { model: "gpt54", incognito: false });