fix(config): respect configured model
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 (1–50) |
|
||||
| `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
@@ -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
@@ -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)";
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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" },
|
||||
];
|
||||
@@ -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 },
|
||||
);
|
||||
});
|
||||
@@ -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 });
|
||||
|
||||
Reference in New Issue
Block a user