@oh-my-pi/pi-coding-agent 16.5.0 → 16.5.2
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/CHANGELOG.md +91 -0
- package/dist/cli.js +3556 -3504
- package/dist/types/advisor/advise-tool.d.ts +12 -1
- package/dist/types/advisor/runtime.d.ts +41 -1
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/update-cli.d.ts +4 -1
- package/dist/types/cli/usage-cli.d.ts +3 -0
- package/dist/types/cli/usage-error.d.ts +4 -0
- package/dist/types/config/api-key-resolver.d.ts +2 -2
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/model-resolver.d.ts +8 -1
- package/dist/types/config/models-config.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +10 -0
- package/dist/types/discovery/substitute-plugin-root.d.ts +22 -0
- package/dist/types/eval/__tests__/process-entry-import.test.d.ts +1 -0
- package/dist/types/eval/backend.d.ts +3 -3
- package/dist/types/eval/bridge-timeout.d.ts +9 -1
- package/dist/types/eval/js/context-manager.d.ts +5 -3
- package/dist/types/eval/js/process-entry.d.ts +6 -0
- package/dist/types/eval/js/worker-core.d.ts +15 -1
- package/dist/types/eval/py/spawn-options.d.ts +10 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +3 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -1
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/extensibility/extensions/wrapper.d.ts +3 -6
- package/dist/types/extensibility/plugins/bun-git-cache.d.ts +3 -0
- package/dist/types/goals/guided-setup.d.ts +12 -0
- package/dist/types/internal-urls/history-protocol.d.ts +3 -2
- package/dist/types/internal-urls/memory-protocol.d.ts +6 -7
- package/dist/types/internal-urls/registry-helpers.d.ts +19 -0
- package/dist/types/main.d.ts +1 -0
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/oauth-flow.d.ts +2 -0
- package/dist/types/modes/components/__tests__/dynamic-border.test.d.ts +1 -0
- package/dist/types/modes/components/agent-hub.d.ts +10 -0
- package/dist/types/modes/components/dynamic-border.d.ts +5 -3
- package/dist/types/modes/components/login-dialog.d.ts +2 -0
- package/dist/types/modes/components/mcp-add-wizard.d.ts +1 -0
- package/dist/types/modes/components/read-tool-group.d.ts +0 -2
- package/dist/types/modes/components/transcript-container.d.ts +3 -2
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/magic-keyword-boundary.d.ts +9 -0
- package/dist/types/modes/orchestrate.d.ts +1 -1
- package/dist/types/modes/rpc/host-tools.d.ts +2 -0
- package/dist/types/modes/rpc/rpc-mode.d.ts +26 -6
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/ultrathink.d.ts +1 -1
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +12 -0
- package/dist/types/modes/workflow.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +6 -0
- package/dist/types/session/exit-diagnostics.d.ts +11 -0
- package/dist/types/session/messages.d.ts +15 -0
- package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +11 -0
- package/dist/types/subprocess/worker-client.d.ts +6 -0
- package/dist/types/tools/bash-skill-urls.d.ts +1 -0
- package/dist/types/tools/grep.d.ts +0 -2
- package/dist/types/tools/read.d.ts +0 -4
- package/dist/types/web/search/provider.d.ts +10 -3
- package/dist/types/web/search/providers/codex.d.ts +5 -4
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +917 -42
- package/src/advisor/advise-tool.ts +17 -1
- package/src/advisor/runtime.ts +270 -67
- package/src/autolearn/controller.ts +15 -3
- package/src/autoresearch/dashboard.ts +2 -2
- package/src/cli/args.ts +12 -0
- package/src/cli/auth-broker-cli.ts +30 -11
- package/src/cli/auth-gateway-cli.ts +5 -1
- package/src/cli/config-cli.ts +15 -3
- package/src/cli/dry-balance-cli.ts +14 -4
- package/src/cli/flag-tables.ts +21 -7
- package/src/cli/update-cli.ts +62 -11
- package/src/cli/usage-cli.ts +58 -5
- package/src/cli/usage-error.ts +7 -0
- package/src/cli.ts +23 -1
- package/src/commands/acp.ts +11 -2
- package/src/commands/launch.ts +12 -3
- package/src/commands/token.ts +3 -1
- package/src/config/api-key-resolver.ts +12 -3
- package/src/config/config-file.ts +30 -12
- package/src/config/model-registry.ts +7 -7
- package/src/config/model-resolver.ts +21 -7
- package/src/config/models-config.ts +1 -1
- package/src/config/settings-schema.ts +10 -0
- package/src/cursor.ts +2 -0
- package/src/discovery/claude-plugins.ts +9 -3
- package/src/discovery/omp-plugins.ts +6 -2
- package/src/discovery/substitute-plugin-root.ts +32 -0
- package/src/eval/__tests__/agent-bridge.test.ts +19 -14
- package/src/eval/__tests__/bridge-timeout.test.ts +106 -0
- package/src/eval/__tests__/js-context-manager.test.ts +158 -1
- package/src/eval/__tests__/kernel-spawn.test.ts +12 -0
- package/src/eval/__tests__/prelude-agent.test.ts +20 -0
- package/src/eval/__tests__/process-entry-import.test.ts +27 -0
- package/src/eval/agent-bridge.ts +121 -116
- package/src/eval/backend.ts +3 -3
- package/src/eval/bridge-timeout.ts +20 -2
- package/src/eval/executor-base.ts +85 -7
- package/src/eval/jl/kernel.ts +2 -1
- package/src/eval/js/context-manager.ts +109 -32
- package/src/eval/js/process-entry.ts +27 -0
- package/src/eval/js/shared/runtime.ts +1 -1
- package/src/eval/js/worker-core.ts +70 -9
- package/src/eval/js/worker-entry.ts +1 -1
- package/src/eval/py/__tests__/prelude.test.ts +72 -0
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/prelude.py +28 -1
- package/src/eval/py/spawn-options.ts +13 -0
- package/src/eval/py/tool-bridge.ts +13 -14
- package/src/eval/rb/kernel.ts +2 -1
- package/src/exec/bash-executor.ts +30 -43
- package/src/extensibility/custom-tools/types.ts +3 -0
- package/src/extensibility/extensions/runner.ts +3 -0
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/extensibility/extensions/wrapper.ts +18 -18
- package/src/extensibility/plugins/bun-git-cache.ts +91 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +32 -16
- package/src/extensibility/plugins/manager.ts +28 -7
- package/src/goals/guided-setup.ts +29 -1
- package/src/internal-urls/history-protocol.ts +95 -15
- package/src/internal-urls/memory-protocol.ts +13 -9
- package/src/internal-urls/registry-helpers.ts +50 -1
- package/src/launch/broker.ts +38 -25
- package/src/lsp/client.ts +7 -1
- package/src/main.ts +29 -0
- package/src/mcp/oauth-discovery.ts +20 -1
- package/src/mcp/oauth-flow.ts +3 -1
- package/src/mcp/tool-bridge.ts +57 -6
- package/src/modes/components/__tests__/dynamic-border.test.ts +55 -0
- package/src/modes/components/agent-dashboard.ts +2 -2
- package/src/modes/components/agent-hub.ts +15 -2
- package/src/modes/components/agent-transcript-viewer.ts +2 -2
- package/src/modes/components/chat-transcript-builder.ts +26 -4
- package/src/modes/components/dynamic-border.ts +9 -6
- package/src/modes/components/extensions/extension-list.ts +2 -2
- package/src/modes/components/hook-selector.ts +10 -4
- package/src/modes/components/login-dialog.ts +5 -0
- package/src/modes/components/mcp-add-wizard.ts +5 -0
- package/src/modes/components/plan-review-overlay.ts +11 -11
- package/src/modes/components/read-tool-group.ts +1 -8
- package/src/modes/components/status-line/component.ts +10 -1
- package/src/modes/components/transcript-container.ts +110 -7
- package/src/modes/controllers/command-controller.ts +12 -4
- package/src/modes/controllers/event-controller.ts +80 -15
- package/src/modes/controllers/input-controller.ts +4 -2
- package/src/modes/controllers/mcp-command-controller.ts +6 -7
- package/src/modes/controllers/selector-controller.ts +24 -5
- package/src/modes/controllers/todo-command-controller.ts +18 -14
- package/src/modes/interactive-mode.ts +7 -3
- package/src/modes/magic-keyword-boundary.ts +23 -0
- package/src/modes/orchestrate.ts +6 -5
- package/src/modes/print-mode.ts +9 -0
- package/src/modes/prompt-action-autocomplete.ts +6 -1
- package/src/modes/rpc/host-tools.ts +15 -0
- package/src/modes/rpc/rpc-mode.ts +123 -48
- package/src/modes/types.ts +1 -1
- package/src/modes/ultrathink.ts +6 -5
- package/src/modes/utils/transcript-render-helpers.ts +54 -0
- package/src/modes/utils/ui-helpers.ts +27 -1
- package/src/modes/workflow.ts +6 -5
- package/src/prompts/advisor/system.md +1 -0
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/grep.md +1 -2
- package/src/prompts/tools/read.md +2 -4
- package/src/sdk.ts +61 -34
- package/src/session/agent-session.ts +283 -39
- package/src/session/exit-diagnostics.ts +108 -0
- package/src/session/messages.test.ts +66 -0
- package/src/session/messages.ts +37 -0
- package/src/session/streaming-output.ts +40 -12
- package/src/slash-commands/helpers/active-oauth-account.ts +22 -2
- package/src/slash-commands/helpers/logout.ts +23 -3
- package/src/slash-commands/helpers/usage-report.ts +14 -2
- package/src/subprocess/worker-client.ts +9 -2
- package/src/system-prompt.test.ts +36 -0
- package/src/system-prompt.ts +1 -1
- package/src/task/executor.ts +8 -0
- package/src/task/render.test.ts +36 -0
- package/src/task/render.ts +55 -43
- package/src/tools/bash-skill-urls.ts +4 -1
- package/src/tools/bash.ts +1 -0
- package/src/tools/browser/registry.ts +17 -3
- package/src/tools/eval.ts +14 -9
- package/src/tools/gh.ts +3 -1
- package/src/tools/grep.ts +5 -45
- package/src/tools/path-utils.ts +7 -1
- package/src/tools/read.ts +23 -74
- package/src/tools/write.ts +82 -9
- package/src/tools/yield.ts +29 -1
- package/src/utils/title-generator.ts +10 -6
- package/src/web/search/index.ts +39 -22
- package/src/web/search/provider.ts +33 -16
- package/src/web/search/providers/codex.ts +68 -21
- package/src/web/search/providers/perplexity-auth.ts +20 -11
- package/src/web/search/providers/perplexity.ts +14 -2
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
* SQLite store, never POSTs the broker sentinel to an OpenAI token endpoint.
|
|
8
8
|
*/
|
|
9
9
|
import * as os from "node:os";
|
|
10
|
-
import { type AuthStorage, type FetchImpl, type OAuthAccess, withOAuthAccess } from "@oh-my-pi/pi-ai";
|
|
10
|
+
import { type AuthStorage, type FetchImpl, type Model, type OAuthAccess, withOAuthAccess } from "@oh-my-pi/pi-ai";
|
|
11
11
|
import { decodeJwt } from "@oh-my-pi/pi-ai/oauth/openai-codex";
|
|
12
|
+
import { applyCodexResponsesLiteShape } from "@oh-my-pi/pi-ai/providers/openai-codex/request-transformer";
|
|
13
|
+
import { createOpenAICodexCompatibilityMetadata } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
12
14
|
import { getBundledModels } from "@oh-my-pi/pi-catalog/models";
|
|
15
|
+
import { CODEX_CLIENT_VERSION, OPENAI_HEADER_VALUES, OPENAI_HEADERS } from "@oh-my-pi/pi-catalog/wire/codex";
|
|
13
16
|
import { $env, readSseJson } from "@oh-my-pi/pi-utils";
|
|
14
17
|
import packageJson from "../../../../package.json" with { type: "json" };
|
|
15
18
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
@@ -22,6 +25,9 @@ const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
|
|
|
22
25
|
const CODEX_RESPONSES_PATH = "/codex/responses";
|
|
23
26
|
const FALLBACK_MODEL = "gpt-5.5";
|
|
24
27
|
const DEFAULT_MODEL_PREFERENCES = [
|
|
28
|
+
"gpt-5.6-luna",
|
|
29
|
+
"gpt-5.6-terra",
|
|
30
|
+
"gpt-5.6-sol",
|
|
25
31
|
"gpt-5.5",
|
|
26
32
|
"gpt-5.4",
|
|
27
33
|
"gpt-5-codex",
|
|
@@ -35,15 +41,38 @@ const JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
|
35
41
|
const DEFAULT_INSTRUCTIONS =
|
|
36
42
|
"You are a helpful assistant with web search capabilities. Search the web to answer the user's question accurately and cite your sources.";
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
type CodexSearchModel = Model<"openai-codex-responses">;
|
|
45
|
+
|
|
46
|
+
interface CodexModelCandidate {
|
|
47
|
+
modelId: string;
|
|
48
|
+
catalogModel?: CodexSearchModel;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getBundledCodexModels(): CodexSearchModel[] {
|
|
52
|
+
const models: CodexSearchModel[] = [];
|
|
53
|
+
for (const model of getBundledModels("openai-codex")) {
|
|
54
|
+
if (model.api === "openai-codex-responses") {
|
|
55
|
+
models.push(model as CodexSearchModel);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return models;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getConfiguredModel(): CodexModelCandidate | undefined {
|
|
39
62
|
const configuredModel = $env.PI_CODEX_WEB_SEARCH_MODEL?.trim();
|
|
40
|
-
|
|
63
|
+
if (!configuredModel) return undefined;
|
|
64
|
+
|
|
65
|
+
const catalogModel = getBundledCodexModels().find(model => model.id === configuredModel);
|
|
66
|
+
return { modelId: configuredModel, ...(catalogModel ? { catalogModel } : {}) };
|
|
41
67
|
}
|
|
42
68
|
|
|
43
|
-
function getDefaultModelCandidates():
|
|
44
|
-
const bundledModels =
|
|
45
|
-
const
|
|
46
|
-
const
|
|
69
|
+
function getDefaultModelCandidates(): CodexModelCandidate[] {
|
|
70
|
+
const bundledModels = getBundledCodexModels();
|
|
71
|
+
const candidates: CodexModelCandidate[] = [];
|
|
72
|
+
for (const modelId of DEFAULT_MODEL_PREFERENCES) {
|
|
73
|
+
const catalogModel = bundledModels.find(model => model.id === modelId);
|
|
74
|
+
if (catalogModel) candidates.push({ modelId, catalogModel });
|
|
75
|
+
}
|
|
47
76
|
|
|
48
77
|
if (candidates.length > 0) {
|
|
49
78
|
return candidates;
|
|
@@ -51,10 +80,11 @@ function getDefaultModelCandidates(): string[] {
|
|
|
51
80
|
|
|
52
81
|
const nonMini = bundledModels.find(model => !model.id.includes("mini") && !model.id.includes("spark"));
|
|
53
82
|
if (nonMini) {
|
|
54
|
-
return [nonMini.id];
|
|
83
|
+
return [{ modelId: nonMini.id, catalogModel: nonMini }];
|
|
55
84
|
}
|
|
56
85
|
|
|
57
|
-
|
|
86
|
+
const fallbackModel = bundledModels[0];
|
|
87
|
+
return fallbackModel ? [{ modelId: fallbackModel.id, catalogModel: fallbackModel }] : [{ modelId: FALLBACK_MODEL }];
|
|
58
88
|
}
|
|
59
89
|
|
|
60
90
|
function shouldRetryWithNextDefaultModel(error: unknown): boolean {
|
|
@@ -301,9 +331,10 @@ async function findCodexAuth(
|
|
|
301
331
|
function buildCodexHeaders(accessToken: string, accountId: string): Record<string, string> {
|
|
302
332
|
return {
|
|
303
333
|
Authorization: `Bearer ${accessToken}`,
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
334
|
+
[OPENAI_HEADERS.ACCOUNT_ID]: accountId,
|
|
335
|
+
[OPENAI_HEADERS.BETA]: OPENAI_HEADER_VALUES.BETA_RESPONSES,
|
|
336
|
+
[OPENAI_HEADERS.ORIGINATOR]: OPENAI_HEADER_VALUES.ORIGINATOR_CODEX,
|
|
337
|
+
[OPENAI_HEADERS.VERSION]: CODEX_CLIENT_VERSION,
|
|
307
338
|
"User-Agent": `pi/${packageJson.version} (${os.platform()} ${os.release()}; ${os.arch()})`,
|
|
308
339
|
Accept: "text/event-stream",
|
|
309
340
|
"Content-Type": "application/json",
|
|
@@ -323,7 +354,8 @@ async function callCodexSearch(
|
|
|
323
354
|
signal?: AbortSignal;
|
|
324
355
|
systemPrompt?: string;
|
|
325
356
|
searchContextSize?: "low" | "medium" | "high";
|
|
326
|
-
|
|
357
|
+
model: CodexModelCandidate;
|
|
358
|
+
sessionId?: string;
|
|
327
359
|
fetch?: FetchImpl;
|
|
328
360
|
},
|
|
329
361
|
): Promise<{
|
|
@@ -336,7 +368,8 @@ async function callCodexSearch(
|
|
|
336
368
|
const url = `${CODEX_BASE_URL}${CODEX_RESPONSES_PATH}`;
|
|
337
369
|
const headers = buildCodexHeaders(auth.accessToken, auth.accountId);
|
|
338
370
|
|
|
339
|
-
const requestedModel = options.modelId;
|
|
371
|
+
const requestedModel = options.model.modelId;
|
|
372
|
+
const usesResponsesLite = options.model.catalogModel?.useResponsesLite === true;
|
|
340
373
|
|
|
341
374
|
const body: Record<string, unknown> = {
|
|
342
375
|
model: requestedModel,
|
|
@@ -358,6 +391,18 @@ async function callCodexSearch(
|
|
|
358
391
|
tool_choice: { type: "web_search" },
|
|
359
392
|
instructions: options.systemPrompt ?? DEFAULT_INSTRUCTIONS,
|
|
360
393
|
};
|
|
394
|
+
if (usesResponsesLite) {
|
|
395
|
+
const metadata = createOpenAICodexCompatibilityMetadata({
|
|
396
|
+
sessionId: options.sessionId,
|
|
397
|
+
requestKind: "turn",
|
|
398
|
+
startNewTurn: true,
|
|
399
|
+
});
|
|
400
|
+
Object.assign(headers, metadata.headers);
|
|
401
|
+
headers[OPENAI_HEADERS.RESPONSES_LITE] = "true";
|
|
402
|
+
body.client_metadata = metadata.clientMetadata;
|
|
403
|
+
body.reasoning = { context: "all_turns" };
|
|
404
|
+
applyCodexResponsesLiteShape(body);
|
|
405
|
+
}
|
|
361
406
|
|
|
362
407
|
const fetchImpl = options.fetch ?? fetch;
|
|
363
408
|
const response = await fetchImpl(url, {
|
|
@@ -489,10 +534,11 @@ async function callCodexSearch(
|
|
|
489
534
|
* Default-model behavior:
|
|
490
535
|
* - If `PI_CODEX_WEB_SEARCH_MODEL` is set, use it exactly once and surface any
|
|
491
536
|
* upstream error verbatim.
|
|
492
|
-
* - Otherwise prefer ChatGPT-account-safe bundled defaults (GPT-5.
|
|
493
|
-
*
|
|
494
|
-
* known 400 "model is not supported" family. This avoids
|
|
495
|
-
* `gpt-5-codex-mini` first on ChatGPT accounts, which OpenAI
|
|
537
|
+
* - Otherwise prefer ChatGPT-account-safe bundled defaults (GPT-5.6 Luna,
|
|
538
|
+
* Terra, Sol, GPT-5.5, …) and retry the next candidate only when Codex
|
|
539
|
+
* returns the known 400 "model is not supported" family. This avoids
|
|
540
|
+
* selecting `gpt-5-codex-mini` first on ChatGPT accounts, which OpenAI
|
|
541
|
+
* rejects.
|
|
496
542
|
*/
|
|
497
543
|
export async function searchCodex(params: SearchParams): Promise<SearchResponse> {
|
|
498
544
|
const seed = await findCodexAuth(params.authStorage, params.sessionId, params.signal);
|
|
@@ -520,15 +566,16 @@ export async function searchCodex(params: SearchParams): Promise<SearchResponse>
|
|
|
520
566
|
|
|
521
567
|
let lastError: unknown;
|
|
522
568
|
for (let index = 0; index < modelCandidates.length; index += 1) {
|
|
523
|
-
const
|
|
524
|
-
if (!
|
|
569
|
+
const candidate = modelCandidates[index];
|
|
570
|
+
if (!candidate) continue;
|
|
525
571
|
|
|
526
572
|
try {
|
|
527
573
|
return await callCodexSearch(auth, params.query, {
|
|
528
574
|
signal: params.signal,
|
|
529
575
|
systemPrompt: params.systemPrompt,
|
|
530
576
|
searchContextSize: "high",
|
|
531
|
-
|
|
577
|
+
model: candidate,
|
|
578
|
+
sessionId: params.sessionId,
|
|
532
579
|
fetch: params.fetch,
|
|
533
580
|
});
|
|
534
581
|
} catch (error) {
|
|
@@ -44,17 +44,26 @@ export async function getApiConfigs(
|
|
|
44
44
|
const useResponses = $env.PI_PERPLEXITY_RESPONSES === "1";
|
|
45
45
|
const configs: ApiConfig[] = [];
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
// A Perplexity OAuth session and a real API key are mutually exclusive here:
|
|
48
|
+
// when the active credential origin is OAuth, `getApiKey("perplexity")`
|
|
49
|
+
// returns the OAuth session JWT (OAuth wins in AuthStorage.getApiKey), not an
|
|
50
|
+
// api.perplexity.ai key. Emitting it as a direct api-key config makes the
|
|
51
|
+
// search loop send the session token as a Bearer to the direct API endpoint,
|
|
52
|
+
// which rejects it with 401 and masks the real (transport) failure — see #5315.
|
|
53
|
+
// Skip the direct config in that case; the OAuth ask-endpoint method covers it.
|
|
54
|
+
if (authStorage.getCredentialOrigin("perplexity")?.kind !== "oauth") {
|
|
55
|
+
const perplexityKey = await authStorage.getApiKey("perplexity", sessionId, options);
|
|
56
|
+
if (perplexityKey) {
|
|
57
|
+
configs.push({
|
|
58
|
+
type: "api_key",
|
|
59
|
+
apiKey: perplexityKey,
|
|
60
|
+
provider: "perplexity",
|
|
61
|
+
chatBaseUrl: PERPLEXITY_CHAT_BASE_URL,
|
|
62
|
+
responsesBaseUrl: PERPLEXITY_RESPONSES_BASE_URL,
|
|
63
|
+
modelPrefix: "",
|
|
64
|
+
useResponses,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
const openrouterKey = await authStorage.getApiKey("openrouter", sessionId, options);
|
|
@@ -604,7 +604,7 @@ async function callPerplexityAsk(
|
|
|
604
604
|
requestParams.send_back_text_in_streaming_api = true;
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
-
const
|
|
607
|
+
const requestInit = {
|
|
608
608
|
method: "POST",
|
|
609
609
|
headers,
|
|
610
610
|
body: JSON.stringify({
|
|
@@ -612,7 +612,19 @@ async function callPerplexityAsk(
|
|
|
612
612
|
params: requestParams,
|
|
613
613
|
}),
|
|
614
614
|
signal: withHardTimeout(params.signal),
|
|
615
|
-
}
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
// The consumer ask endpoint intermittently drops the socket before sending an
|
|
618
|
+
// HTTP response (#5315). Retry the transport exactly once; once we hold an
|
|
619
|
+
// HTTP response (handled below) the outcome — including non-2xx — is final and
|
|
620
|
+
// never retried, so a real 401/429 is never papered over by a second attempt.
|
|
621
|
+
let response: Response;
|
|
622
|
+
try {
|
|
623
|
+
response = await (params.fetch ?? fetch)(PERPLEXITY_OAUTH_ASK_URL, requestInit);
|
|
624
|
+
} catch (error) {
|
|
625
|
+
if (params.signal?.aborted) throw error;
|
|
626
|
+
response = await (params.fetch ?? fetch)(PERPLEXITY_OAUTH_ASK_URL, requestInit);
|
|
627
|
+
}
|
|
616
628
|
|
|
617
629
|
if (!response.ok) {
|
|
618
630
|
const errorText = await response.text();
|