@oh-my-pi/pi-coding-agent 13.2.0 → 13.3.0
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 +54 -1
- package/package.json +7 -7
- package/scripts/format-prompts.ts +33 -14
- package/scripts/generate-docs-index.ts +2 -2
- package/src/capability/index.ts +1 -2
- package/src/cli/args.ts +3 -3
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/file-processor.ts +1 -2
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/jupyter-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/shell-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +1 -1
- package/src/cli/stats-cli.ts +1 -2
- package/src/cli/update-cli.ts +1 -2
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/launch.ts +2 -1
- package/src/commit/agentic/agent.ts +2 -1
- package/src/commit/agentic/index.ts +1 -2
- package/src/commit/agentic/prompts/system.md +3 -3
- package/src/commit/agentic/tools/propose-changelog.ts +30 -19
- package/src/commit/changelog/generate.ts +16 -6
- package/src/commit/changelog/index.ts +2 -1
- package/src/commit/pipeline.ts +1 -2
- package/src/commit/prompts/reduce-system.md +1 -1
- package/src/commit/types.ts +10 -1
- package/src/config/keybindings.ts +1 -2
- package/src/config/model-registry.ts +1 -1
- package/src/config/prompt-templates.ts +14 -2
- package/src/config/settings-schema.ts +36 -4
- package/src/config/settings.ts +19 -2
- package/src/config.ts +1 -2
- package/src/debug/index.ts +1 -1
- package/src/debug/report-bundle.ts +1 -2
- package/src/debug/system-info.ts +1 -2
- package/src/discovery/agents.ts +2 -2
- package/src/discovery/builtin.ts +8 -9
- package/src/discovery/claude-plugins.ts +2 -2
- package/src/discovery/claude.ts +30 -12
- package/src/discovery/codex.ts +3 -3
- package/src/discovery/cursor.ts +5 -4
- package/src/discovery/gemini.ts +5 -5
- package/src/discovery/helpers.ts +47 -69
- package/src/discovery/mcp-json.ts +3 -3
- package/src/discovery/opencode.ts +7 -8
- package/src/discovery/ssh.ts +3 -3
- package/src/discovery/vscode.ts +3 -2
- package/src/discovery/windsurf.ts +3 -2
- package/src/exa/company.ts +1 -1
- package/src/exa/factory.ts +1 -6
- package/src/exa/linkedin.ts +1 -1
- package/src/exa/mcp-client.ts +19 -8
- package/src/exa/search.ts +2 -2
- package/src/exa/types.ts +3 -3
- package/src/exec/bash-executor.ts +2 -1
- package/src/exec/non-interactive-env.ts +43 -0
- package/src/export/custom-share.ts +1 -1
- package/src/export/html/index.ts +1 -2
- package/src/extensibility/custom-commands/loader.ts +1 -2
- package/src/extensibility/plugins/installer.ts +1 -2
- package/src/extensibility/plugins/loader.ts +1 -2
- package/src/extensibility/plugins/manager.ts +3 -2
- package/src/extensibility/skills.ts +59 -115
- package/src/index.ts +1 -3
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/ipy/executor.ts +1 -2
- package/src/ipy/gateway-coordinator.ts +1 -2
- package/src/ipy/modules.ts +1 -1
- package/src/ipy/runtime.ts +2 -3
- package/src/main.ts +1 -2
- package/src/mcp/config.ts +2 -2
- package/src/mcp/transports/stdio.ts +1 -2
- package/src/memories/index.ts +1 -2
- package/src/modes/components/extensions/extension-dashboard.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +8 -2
- package/src/modes/components/footer.ts +1 -2
- package/src/modes/components/settings-defs.ts +17 -1
- package/src/modes/components/status-line/segments.ts +1 -2
- package/src/modes/components/status-line.ts +7 -5
- package/src/modes/components/tool-execution.ts +3 -10
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/command-controller.ts +1 -2
- package/src/modes/controllers/mcp-command-controller.ts +5 -4
- package/src/modes/controllers/selector-controller.ts +22 -1
- package/src/modes/controllers/ssh-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +11 -3
- package/src/modes/oauth-manual-input.ts +42 -0
- package/src/modes/shared.ts +1 -2
- package/src/modes/theme/theme.ts +1 -2
- package/src/modes/types.ts +2 -0
- package/src/patch/hashline.ts +19 -1
- package/src/patch/index.ts +1 -25
- package/src/prompts/agents/designer.md +7 -10
- package/src/prompts/agents/explore.md +15 -23
- package/src/prompts/agents/init.md +23 -23
- package/src/prompts/agents/plan.md +14 -77
- package/src/prompts/agents/reviewer.md +6 -5
- package/src/prompts/agents/task.md +13 -11
- package/src/prompts/compaction/branch-summary.md +3 -3
- package/src/prompts/compaction/compaction-short-summary.md +7 -7
- package/src/prompts/compaction/compaction-summary-context.md +1 -1
- package/src/prompts/compaction/compaction-summary.md +5 -5
- package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
- package/src/prompts/compaction/compaction-update-summary.md +11 -11
- package/src/prompts/memories/consolidation.md +5 -5
- package/src/prompts/memories/read-path.md +6 -6
- package/src/prompts/memories/stage_one_input.md +1 -1
- package/src/prompts/memories/stage_one_system.md +5 -5
- package/src/prompts/review-request.md +4 -4
- package/src/prompts/system/agent-creation-architect.md +17 -17
- package/src/prompts/system/agent-creation-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +2 -0
- package/src/prompts/system/custom-system-prompt.md +4 -4
- package/src/prompts/system/plan-mode-active.md +20 -20
- package/src/prompts/system/plan-mode-approved.md +7 -7
- package/src/prompts/system/plan-mode-reference.md +2 -2
- package/src/prompts/system/plan-mode-subagent.md +8 -8
- package/src/prompts/system/subagent-submit-reminder.md +5 -5
- package/src/prompts/system/subagent-system-prompt.md +29 -22
- package/src/prompts/system/subagent-user-prompt.md +7 -3
- package/src/prompts/system/summarization-system.md +1 -1
- package/src/prompts/system/system-prompt.md +214 -226
- package/src/prompts/system/title-system.md +2 -2
- package/src/prompts/system/ttsr-interrupt.md +1 -1
- package/src/prompts/system/web-search.md +16 -16
- package/src/prompts/tools/ask.md +1 -3
- package/src/prompts/tools/await.md +2 -4
- package/src/prompts/tools/bash.md +5 -7
- package/src/prompts/tools/browser.md +4 -6
- package/src/prompts/tools/calculator.md +1 -3
- package/src/prompts/tools/cancel-job.md +2 -4
- package/src/prompts/tools/exit-plan-mode.md +7 -7
- package/src/prompts/tools/fetch.md +0 -2
- package/src/prompts/tools/find.md +3 -5
- package/src/prompts/tools/gemini-image.md +6 -22
- package/src/prompts/tools/grep.md +4 -6
- package/src/prompts/tools/hashline.md +56 -15
- package/src/prompts/tools/lsp.md +1 -3
- package/src/prompts/tools/patch.md +7 -9
- package/src/prompts/tools/python.md +10 -14
- package/src/prompts/tools/read.md +0 -2
- package/src/prompts/tools/replace.md +5 -7
- package/src/prompts/tools/ssh.md +3 -5
- package/src/prompts/tools/task-summary.md +4 -4
- package/src/prompts/tools/task.md +7 -9
- package/src/prompts/tools/todo-write.md +7 -9
- package/src/prompts/tools/web-search.md +3 -5
- package/src/prompts/tools/write.md +3 -5
- package/src/sdk.ts +4 -2
- package/src/session/agent-session.ts +10 -26
- package/src/session/agent-storage.ts +1 -2
- package/src/session/history-storage.ts +1 -2
- package/src/session/session-manager.ts +10 -2
- package/src/slash-commands/builtin-registry.ts +26 -1
- package/src/ssh/connection-manager.ts +11 -2
- package/src/ssh/sshfs-mount.ts +7 -1
- package/src/system-prompt.ts +29 -103
- package/src/task/agents.ts +1 -1
- package/src/task/index.ts +211 -70
- package/src/task/render.ts +24 -8
- package/src/task/types.ts +6 -1
- package/src/task/worktree.ts +394 -32
- package/src/tools/ask.ts +0 -1
- package/src/tools/bash-interactive.ts +2 -45
- package/src/tools/bash.ts +5 -5
- package/src/tools/browser.ts +1 -2
- package/src/tools/gemini-image.ts +8 -28
- package/src/tools/json-tree.ts +2 -1
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +1 -2
- package/src/tools/submit-result.ts +22 -23
- package/src/utils/commit-message-generator.ts +132 -0
- package/src/utils/tools-manager.ts +1 -2
- package/src/web/scrapers/artifacthub.ts +2 -1
- package/src/web/scrapers/aur.ts +2 -1
- package/src/web/scrapers/biorxiv.ts +2 -1
- package/src/web/scrapers/bluesky.ts +2 -1
- package/src/web/scrapers/chocolatey.ts +2 -1
- package/src/web/scrapers/cisa-kev.ts +2 -1
- package/src/web/scrapers/clojars.ts +2 -1
- package/src/web/scrapers/coingecko.ts +2 -1
- package/src/web/scrapers/crates-io.ts +2 -1
- package/src/web/scrapers/crossref.ts +2 -1
- package/src/web/scrapers/discogs.ts +3 -1
- package/src/web/scrapers/discourse.ts +2 -1
- package/src/web/scrapers/dockerhub.ts +2 -1
- package/src/web/scrapers/fdroid.ts +2 -1
- package/src/web/scrapers/firefox-addons.ts +2 -1
- package/src/web/scrapers/flathub.ts +2 -1
- package/src/web/scrapers/gitlab.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +2 -1
- package/src/web/scrapers/hackage.ts +2 -1
- package/src/web/scrapers/hackernews.ts +2 -1
- package/src/web/scrapers/hex.ts +2 -1
- package/src/web/scrapers/huggingface.ts +2 -1
- package/src/web/scrapers/jetbrains-marketplace.ts +2 -1
- package/src/web/scrapers/lemmy.ts +2 -1
- package/src/web/scrapers/lobsters.ts +2 -1
- package/src/web/scrapers/mastodon.ts +2 -1
- package/src/web/scrapers/maven.ts +2 -1
- package/src/web/scrapers/mdn.ts +2 -1
- package/src/web/scrapers/metacpan.ts +2 -1
- package/src/web/scrapers/musicbrainz.ts +3 -1
- package/src/web/scrapers/npm.ts +2 -1
- package/src/web/scrapers/nuget.ts +2 -1
- package/src/web/scrapers/nvd.ts +2 -1
- package/src/web/scrapers/ollama.ts +2 -1
- package/src/web/scrapers/open-vsx.ts +2 -1
- package/src/web/scrapers/opencorporates.ts +2 -1
- package/src/web/scrapers/openlibrary.ts +2 -1
- package/src/web/scrapers/orcid.ts +3 -1
- package/src/web/scrapers/osv.ts +2 -1
- package/src/web/scrapers/packagist.ts +2 -1
- package/src/web/scrapers/pub-dev.ts +2 -1
- package/src/web/scrapers/pubmed.ts +2 -1
- package/src/web/scrapers/pypi.ts +2 -1
- package/src/web/scrapers/rawg.ts +2 -8
- package/src/web/scrapers/reddit.ts +2 -1
- package/src/web/scrapers/repology.ts +2 -1
- package/src/web/scrapers/rfc.ts +2 -1
- package/src/web/scrapers/rubygems.ts +2 -1
- package/src/web/scrapers/searchcode.ts +2 -1
- package/src/web/scrapers/sec-edgar.ts +2 -1
- package/src/web/scrapers/semantic-scholar.ts +2 -1
- package/src/web/scrapers/snapcraft.ts +2 -1
- package/src/web/scrapers/sourcegraph.ts +2 -1
- package/src/web/scrapers/spdx.ts +2 -1
- package/src/web/scrapers/stackoverflow.ts +2 -1
- package/src/web/scrapers/terraform.ts +2 -1
- package/src/web/scrapers/types.ts +0 -11
- package/src/web/scrapers/vimeo.ts +2 -1
- package/src/web/scrapers/vscode-marketplace.ts +2 -1
- package/src/web/scrapers/w3c.ts +2 -1
- package/src/web/scrapers/wikidata.ts +2 -1
- package/src/web/search/index.ts +10 -14
- package/src/web/search/provider.ts +2 -2
- package/src/web/search/providers/codex.ts +1 -2
- package/src/web/search/providers/exa.ts +42 -10
- package/src/web/search/providers/gemini.ts +1 -1
- package/src/web/search/providers/perplexity.ts +20 -9
- package/src/web/search/providers/utils.ts +1 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MusicBrainz URL handler for artists, releases, and recordings
|
|
3
3
|
*/
|
|
4
|
+
|
|
5
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
4
6
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
5
|
-
import { buildResult, formatMediaDuration, loadPage
|
|
7
|
+
import { buildResult, formatMediaDuration, loadPage } from "./types";
|
|
6
8
|
|
|
7
9
|
type MusicBrainzEntity = "artist" | "release" | "recording";
|
|
8
10
|
|
package/src/web/scrapers/npm.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Handle npm URLs via registry API
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatIsoDate, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatIsoDate, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface NuGetCatalogEntry {
|
|
5
6
|
id: string;
|
package/src/web/scrapers/nvd.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatIsoDate, loadPage
|
|
3
|
+
import { buildResult, formatIsoDate, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface CvssV31 {
|
|
5
6
|
baseScore: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import { formatBytes } from "../../tools/render-utils";
|
|
2
3
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
3
|
-
import { buildResult, decodeHtmlEntities, loadPage
|
|
4
|
+
import { buildResult, decodeHtmlEntities, loadPage } from "./types";
|
|
4
5
|
|
|
5
6
|
interface OllamaTagDetails {
|
|
6
7
|
parent_model?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface OpenVsxFileLinks {
|
|
5
6
|
readme?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, loadPage
|
|
3
|
+
import { buildResult, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface OpenLibraryAuthor {
|
|
5
6
|
name?: string;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ORCID handler for web-fetch
|
|
3
3
|
*/
|
|
4
|
+
|
|
5
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
4
6
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
5
|
-
import { buildResult, loadPage
|
|
7
|
+
import { buildResult, loadPage } from "./types";
|
|
6
8
|
|
|
7
9
|
const MAX_WORKS = 50;
|
|
8
10
|
const ORCID_PATTERN = /\/(\d{4}-\d{4}-\d{4}-\d{3}[\dXx])(?:\/|$)/;
|
package/src/web/scrapers/osv.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatIsoDate, loadPage
|
|
3
|
+
import { buildResult, formatIsoDate, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface OsvSeverity {
|
|
5
6
|
type: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Handle Packagist URLs via JSON API
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { buildResult, formatNumber, htmlToBasicMarkdown, loadPage, type SpecialHandler } from "./types";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Handle pub.dev URLs via API
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PubMed handler for web-fetch
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { buildResult, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
5
6
|
|
|
6
7
|
const NCBI_HEADERS = {
|
|
7
8
|
Accept: "application/json, text/plain;q=0.9, */*;q=0.8",
|
package/src/web/scrapers/pypi.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { buildResult, formatNumber, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Handle PyPI URLs via JSON API
|
package/src/web/scrapers/rawg.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
htmlToBasicMarkdown,
|
|
4
|
-
loadPage,
|
|
5
|
-
type RenderResult,
|
|
6
|
-
type SpecialHandler,
|
|
7
|
-
tryParseJson,
|
|
8
|
-
} from "./types";
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { buildResult, htmlToBasicMarkdown, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
9
3
|
|
|
10
4
|
interface RawgPlatformEntry {
|
|
11
5
|
platform?: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { buildResult, formatIsoDate, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
2
3
|
|
|
3
4
|
interface RedditPost {
|
|
4
5
|
title: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { buildResult, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
2
3
|
|
|
3
4
|
interface RepologyPackage {
|
|
4
5
|
repo: string;
|
package/src/web/scrapers/rfc.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { buildResult, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
2
3
|
|
|
3
4
|
interface RfcMetadata {
|
|
4
5
|
doc_id: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { buildResult, formatNumber, loadPage, type RenderResult, type SpecialHandler } from "./types";
|
|
2
3
|
|
|
3
4
|
interface RubyGemsDependency {
|
|
4
5
|
name: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface SearchcodeResult {
|
|
5
6
|
id?: number | string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, loadPage
|
|
3
|
+
import { buildResult, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface SecFiling {
|
|
5
6
|
accessionNumber: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface SemanticScholarAuthor {
|
|
5
6
|
name: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface SnapcraftPublisher {
|
|
5
6
|
"display-name"?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, loadPage
|
|
3
|
+
import { buildResult, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
const GRAPHQL_ENDPOINT = "https://sourcegraph.com/.api/graphql";
|
|
5
6
|
const GRAPHQL_HEADERS = {
|
package/src/web/scrapers/spdx.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, htmlToBasicMarkdown, loadPage
|
|
3
|
+
import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface SpdxCrossRef {
|
|
5
6
|
url?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatIsoDate, htmlToBasicMarkdown, loadPage
|
|
3
|
+
import { buildResult, formatIsoDate, htmlToBasicMarkdown, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface SOQuestion {
|
|
5
6
|
title: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface TerraformModule {
|
|
5
6
|
id: string;
|
|
@@ -190,17 +190,6 @@ export function htmlToBasicMarkdown(html: string): string {
|
|
|
190
190
|
return decodeHtmlEntities(stripped);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
/**
|
|
194
|
-
* Try to parse JSON, returning null on failure.
|
|
195
|
-
*/
|
|
196
|
-
export function tryParseJson<T = unknown>(content: string): T | null {
|
|
197
|
-
try {
|
|
198
|
-
return JSON.parse(content) as T;
|
|
199
|
-
} catch {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
193
|
/**
|
|
205
194
|
* Build a RenderResult from markdown content. Calls finalizeOutput internally.
|
|
206
195
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatMediaDuration, loadPage
|
|
3
|
+
import { buildResult, formatMediaDuration, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface VimeoOEmbed {
|
|
5
6
|
title: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
interface MarketplaceProperty {
|
|
5
6
|
key?: string;
|
package/src/web/scrapers/w3c.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, htmlToBasicMarkdown, loadPage
|
|
3
|
+
import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
|
|
3
4
|
import { asRecord } from "./utils";
|
|
4
5
|
|
|
5
6
|
type JsonRecord = Record<string, unknown>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { tryParseJson } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import type { RenderResult, SpecialHandler } from "./types";
|
|
2
|
-
import { buildResult, formatNumber, loadPage
|
|
3
|
+
import { buildResult, formatNumber, loadPage } from "./types";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Common Wikidata property IDs mapped to human-readable names
|
package/src/web/search/index.ts
CHANGED
|
@@ -353,13 +353,6 @@ async function executeExaTool(
|
|
|
353
353
|
): Promise<{ content: Array<{ type: "text"; text: string }>; details: ExaRenderDetails }> {
|
|
354
354
|
try {
|
|
355
355
|
const apiKey = await findExaKey();
|
|
356
|
-
if (!apiKey) {
|
|
357
|
-
return {
|
|
358
|
-
content: [{ type: "text" as const, text: "Error: EXA_API_KEY not found" }],
|
|
359
|
-
details: { error: "EXA_API_KEY not found", toolName },
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
|
|
363
356
|
const response = await callExaTool(mcpToolName, params, apiKey);
|
|
364
357
|
|
|
365
358
|
if (isSearchResponse(response)) {
|
|
@@ -402,7 +395,7 @@ Parameters:
|
|
|
402
395
|
|
|
403
396
|
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
|
404
397
|
const { num_results, ...rest } = params as Record<string, unknown>;
|
|
405
|
-
const args = { ...rest, type: "
|
|
398
|
+
const args = { ...rest, type: "auto", numResults: num_results ?? 10 };
|
|
406
399
|
return executeExaTool("web_search_exa", args, "web_search_deep");
|
|
407
400
|
},
|
|
408
401
|
|
|
@@ -462,7 +455,7 @@ Parameters:
|
|
|
462
455
|
parameters: webSearchCrawlSchema,
|
|
463
456
|
|
|
464
457
|
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
|
465
|
-
return executeExaTool("
|
|
458
|
+
return executeExaTool("crawling_exa", params as Record<string, unknown>, "web_search_crawl");
|
|
466
459
|
},
|
|
467
460
|
|
|
468
461
|
renderCall(args, _options, theme) {
|
|
@@ -493,7 +486,7 @@ Parameters:
|
|
|
493
486
|
parameters: webSearchLinkedinSchema,
|
|
494
487
|
|
|
495
488
|
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
|
496
|
-
return executeExaTool("
|
|
489
|
+
return executeExaTool("linkedin_search_exa", params as Record<string, unknown>, "web_search_linkedin");
|
|
497
490
|
},
|
|
498
491
|
|
|
499
492
|
renderCall(args, _options, theme) {
|
|
@@ -523,7 +516,7 @@ Parameters:
|
|
|
523
516
|
parameters: webSearchCompanySchema,
|
|
524
517
|
|
|
525
518
|
async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
|
|
526
|
-
return executeExaTool("
|
|
519
|
+
return executeExaTool("company_research_exa", params as Record<string, unknown>, "web_search_company");
|
|
527
520
|
},
|
|
528
521
|
|
|
529
522
|
renderCall(args, _options, theme) {
|
|
@@ -561,17 +554,20 @@ export interface SearchToolsOptions {
|
|
|
561
554
|
*
|
|
562
555
|
* Returns:
|
|
563
556
|
* - Always: web_search (unified, works with Anthropic/Perplexity/Exa)
|
|
564
|
-
* -
|
|
557
|
+
* - Always: web_search_deep, web_search_code_context (public Exa MCP tools)
|
|
558
|
+
* - With EXA_API_KEY: web_search_crawl
|
|
565
559
|
* - With EXA_API_KEY + options.enableLinkedin: web_search_linkedin
|
|
566
560
|
* - With EXA_API_KEY + options.enableCompany: web_search_company
|
|
567
561
|
*/
|
|
568
562
|
export async function getSearchTools(options: SearchToolsOptions = {}): Promise<CustomTool<any, any>[]> {
|
|
569
563
|
const tools: CustomTool<any, any>[] = [webSearchCustomTool];
|
|
570
564
|
|
|
571
|
-
|
|
565
|
+
tools.push(webSearchDeepTool, webSearchCodeContextTool);
|
|
566
|
+
|
|
567
|
+
// Advanced/add-on tools remain key-gated to avoid exposing known unauthenticated failures
|
|
572
568
|
const exaKey = await findExaKey();
|
|
573
569
|
if (exaKey) {
|
|
574
|
-
tools.push(
|
|
570
|
+
tools.push(webSearchCrawlTool);
|
|
575
571
|
|
|
576
572
|
if (options.enableLinkedin) {
|
|
577
573
|
tools.push(...linkedinSearchTools);
|
|
@@ -29,7 +29,6 @@ const SEARCH_PROVIDERS: Record<SearchProviderId, SearchProvider> = {
|
|
|
29
29
|
|
|
30
30
|
export const SEARCH_PROVIDER_ORDER: SearchProviderId[] = [
|
|
31
31
|
"perplexity",
|
|
32
|
-
"exa",
|
|
33
32
|
"brave",
|
|
34
33
|
"jina",
|
|
35
34
|
"kimi",
|
|
@@ -37,6 +36,7 @@ export const SEARCH_PROVIDER_ORDER: SearchProviderId[] = [
|
|
|
37
36
|
"gemini",
|
|
38
37
|
"codex",
|
|
39
38
|
"zai",
|
|
39
|
+
"exa",
|
|
40
40
|
"synthetic",
|
|
41
41
|
];
|
|
42
42
|
|
|
@@ -52,7 +52,7 @@ export function setPreferredSearchProvider(provider: SearchProviderId | "auto"):
|
|
|
52
52
|
preferredProvId = provider;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
/** Determine which providers are configured (priority: Perplexity →
|
|
55
|
+
/** Determine which providers are configured (priority: Perplexity → Brave → Jina → Kimi → Anthropic → Gemini → Codex → Z.AI → Exa → Synthetic) */
|
|
56
56
|
export async function resolveProviderChain(
|
|
57
57
|
preferredProvider: SearchProviderId | "auto" = preferredProvId,
|
|
58
58
|
): Promise<SearchProvider[]> {
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
* Returns synthesized answers with web search sources.
|
|
7
7
|
*/
|
|
8
8
|
import * as os from "node:os";
|
|
9
|
-
import { readSseJson } from "@oh-my-pi/pi-utils";
|
|
10
|
-
import { getAgentDbPath } from "@oh-my-pi/pi-utils/dirs";
|
|
9
|
+
import { getAgentDbPath, readSseJson } from "@oh-my-pi/pi-utils";
|
|
11
10
|
import packageJson from "../../../../package.json" with { type: "json" };
|
|
12
11
|
import { AgentStorage } from "../../../session/agent-storage";
|
|
13
12
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* High-quality neural search via Exa Search API.
|
|
5
5
|
* Returns structured search results with optional content extraction.
|
|
6
|
+
* Requests per-result summaries via `contents.summary` and synthesizes
|
|
7
|
+
* them into a combined `answer` string on the SearchResponse.
|
|
6
8
|
*/
|
|
7
9
|
import { getEnvApiKey } from "@oh-my-pi/pi-ai";
|
|
8
|
-
import { findApiKey as findExaKey } from "../../../exa/mcp-client";
|
|
9
10
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
10
11
|
import { SearchProviderError } from "../../../web/search/types";
|
|
11
12
|
import { dateToAgeSeconds } from "../utils";
|
|
@@ -35,6 +36,7 @@ interface ExaSearchResult {
|
|
|
35
36
|
publishedDate?: string | null;
|
|
36
37
|
text?: string | null;
|
|
37
38
|
highlights?: string[] | null;
|
|
39
|
+
summary?: string | null;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
interface ExaSearchResponse {
|
|
@@ -45,18 +47,41 @@ interface ExaSearchResponse {
|
|
|
45
47
|
searchTime?: number;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
function normalizeSearchType(type: ExaSearchParamType | undefined): ExaSearchType {
|
|
50
|
+
export function normalizeSearchType(type: ExaSearchParamType | undefined): ExaSearchType {
|
|
49
51
|
if (!type) return "auto";
|
|
50
52
|
if (type === "keyword") return "fast";
|
|
51
53
|
return type;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
|
-
/**
|
|
55
|
-
|
|
56
|
+
/** Maximum number of per-result summaries to include in the synthesized answer. */
|
|
57
|
+
const MAX_ANSWER_SUMMARIES = 3;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Synthesize an answer string from per-result summaries returned by Exa.
|
|
61
|
+
* Returns `undefined` when no non-empty summaries are available so callers
|
|
62
|
+
* can leave `SearchResponse.answer` unset (matching other providers).
|
|
63
|
+
*/
|
|
64
|
+
export function synthesizeAnswer(results: ExaSearchResult[]): string | undefined {
|
|
65
|
+
const parts: string[] = [];
|
|
66
|
+
for (const r of results) {
|
|
67
|
+
if (parts.length >= MAX_ANSWER_SUMMARIES) break;
|
|
68
|
+
const summary = r.summary?.trim();
|
|
69
|
+
if (!summary) continue;
|
|
70
|
+
const title = r.title?.trim() || r.url || "Untitled";
|
|
71
|
+
parts.push(`**${title}**: ${summary}`);
|
|
72
|
+
}
|
|
73
|
+
return parts.length > 0 ? parts.join("\n\n") : undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Build the request body for `callExaSearch`. Exported for testing. */
|
|
77
|
+
export function buildExaRequestBody(params: ExaSearchParams): Record<string, unknown> {
|
|
56
78
|
const body: Record<string, unknown> = {
|
|
57
79
|
query: params.query,
|
|
58
80
|
numResults: params.num_results ?? 10,
|
|
59
81
|
type: normalizeSearchType(params.type),
|
|
82
|
+
contents: {
|
|
83
|
+
summary: { query: params.query },
|
|
84
|
+
},
|
|
60
85
|
};
|
|
61
86
|
|
|
62
87
|
if (params.include_domains?.length) {
|
|
@@ -72,6 +97,13 @@ async function callExaSearch(apiKey: string, params: ExaSearchParams): Promise<E
|
|
|
72
97
|
body.endPublishedDate = params.end_published_date;
|
|
73
98
|
}
|
|
74
99
|
|
|
100
|
+
return body;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Call Exa Search API */
|
|
104
|
+
async function callExaSearch(apiKey: string, params: ExaSearchParams): Promise<ExaSearchResponse> {
|
|
105
|
+
const body = buildExaRequestBody(params);
|
|
106
|
+
|
|
75
107
|
const response = await fetch(EXA_API_URL, {
|
|
76
108
|
method: "POST",
|
|
77
109
|
headers: {
|
|
@@ -107,7 +139,7 @@ export async function searchExa(params: ExaSearchParams): Promise<SearchResponse
|
|
|
107
139
|
sources.push({
|
|
108
140
|
title: result.title ?? result.url,
|
|
109
141
|
url: result.url,
|
|
110
|
-
snippet: result.text
|
|
142
|
+
snippet: result.summary || result.text || result.highlights?.join(" ") || undefined,
|
|
111
143
|
publishedDate: result.publishedDate ?? undefined,
|
|
112
144
|
ageSeconds: dateToAgeSeconds(result.publishedDate ?? undefined),
|
|
113
145
|
author: result.author ?? undefined,
|
|
@@ -118,8 +150,12 @@ export async function searchExa(params: ExaSearchParams): Promise<SearchResponse
|
|
|
118
150
|
// Apply num_results limit if specified
|
|
119
151
|
const limitedSources = params.num_results ? sources.slice(0, params.num_results) : sources;
|
|
120
152
|
|
|
153
|
+
// Synthesize answer only from results that have a URL (same guard as sources loop)
|
|
154
|
+
const answer = response.results ? synthesizeAnswer(response.results.filter(r => !!r.url)) : undefined;
|
|
155
|
+
|
|
121
156
|
return {
|
|
122
157
|
provider: "exa",
|
|
158
|
+
answer,
|
|
123
159
|
sources: limitedSources,
|
|
124
160
|
requestId: response.requestId,
|
|
125
161
|
};
|
|
@@ -131,11 +167,7 @@ export class ExaProvider extends SearchProvider {
|
|
|
131
167
|
readonly label = "Exa";
|
|
132
168
|
|
|
133
169
|
isAvailable(): boolean {
|
|
134
|
-
|
|
135
|
-
return !!findExaKey();
|
|
136
|
-
} catch {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
170
|
+
return true;
|
|
139
171
|
}
|
|
140
172
|
|
|
141
173
|
search(params: SearchParams): Promise<SearchResponse> {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Returns synthesized answers with citations and source metadata from grounding chunks.
|
|
7
7
|
*/
|
|
8
8
|
import { getAntigravityHeaders, getGeminiCliHeaders, refreshGoogleCloudToken } from "@oh-my-pi/pi-ai";
|
|
9
|
-
import { getAgentDbPath } from "@oh-my-pi/pi-utils
|
|
9
|
+
import { getAgentDbPath } from "@oh-my-pi/pi-utils";
|
|
10
10
|
import { AgentStorage } from "../../../session/agent-storage";
|
|
11
11
|
import type { SearchCitation, SearchResponse, SearchSource } from "../../../web/search/types";
|
|
12
12
|
import { SearchProviderError } from "../../../web/search/types";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Perplexity Web Search Provider
|
|
3
3
|
*
|
|
4
|
-
* Supports
|
|
5
|
-
* -
|
|
4
|
+
* Supports three auth modes:
|
|
5
|
+
* - Cookies (`PERPLEXITY_COOKIES`) via `www.perplexity.ai/rest/sse/perplexity_ask`
|
|
6
6
|
* - OAuth JWT (stored in `agent.db`) via `www.perplexity.ai/rest/sse/perplexity_ask`
|
|
7
|
+
* - API key (`PERPLEXITY_API_KEY`) via `api.perplexity.ai/chat/completions`
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import { getEnvApiKey } from "@oh-my-pi/pi-ai";
|
|
10
|
-
import { readSseJson } from "@oh-my-pi/pi-utils";
|
|
11
|
-
import { getAgentDbPath } from "@oh-my-pi/pi-utils/dirs";
|
|
11
|
+
import { $env, getAgentDbPath, readSseJson } from "@oh-my-pi/pi-utils";
|
|
12
12
|
import { AgentStorage } from "../../../session/agent-storage";
|
|
13
13
|
import type {
|
|
14
14
|
PerplexityMessageOutput,
|
|
@@ -47,6 +47,10 @@ type PerplexityAuth =
|
|
|
47
47
|
| {
|
|
48
48
|
type: "oauth";
|
|
49
49
|
token: string;
|
|
50
|
+
}
|
|
51
|
+
| {
|
|
52
|
+
type: "cookies";
|
|
53
|
+
cookies: string;
|
|
50
54
|
};
|
|
51
55
|
|
|
52
56
|
interface PerplexityOAuthStreamMarkdownBlock {
|
|
@@ -189,10 +193,17 @@ async function findOAuthToken(): Promise<string | null> {
|
|
|
189
193
|
}
|
|
190
194
|
|
|
191
195
|
async function findPerplexityAuth(): Promise<PerplexityAuth | null> {
|
|
196
|
+
// 1. PERPLEXITY_COOKIES env var
|
|
197
|
+
const cookies = $env.PERPLEXITY_COOKIES?.trim();
|
|
198
|
+
if (cookies) {
|
|
199
|
+
return { type: "cookies", cookies };
|
|
200
|
+
}
|
|
201
|
+
// 2. OAuth token from agent.db
|
|
192
202
|
const oauthToken = await findOAuthToken();
|
|
193
203
|
if (oauthToken) {
|
|
194
204
|
return { type: "oauth", token: oauthToken };
|
|
195
205
|
}
|
|
206
|
+
// 3. PERPLEXITY_API_KEY env var
|
|
196
207
|
const apiKey = findApiKey();
|
|
197
208
|
if (apiKey) {
|
|
198
209
|
return { type: "api_key", token: apiKey };
|
|
@@ -290,7 +301,7 @@ function buildOAuthAnswer(event: PerplexityOAuthStreamEvent): string {
|
|
|
290
301
|
}
|
|
291
302
|
|
|
292
303
|
async function callPerplexityOAuth(
|
|
293
|
-
|
|
304
|
+
auth: { type: "oauth"; token: string } | { type: "cookies"; cookies: string },
|
|
294
305
|
params: PerplexitySearchParams,
|
|
295
306
|
): Promise<{ answer: string; sources: SearchSource[]; model?: string; requestId?: string }> {
|
|
296
307
|
const requestId = crypto.randomUUID();
|
|
@@ -299,7 +310,7 @@ async function callPerplexityOAuth(
|
|
|
299
310
|
const response = await fetch(PERPLEXITY_OAUTH_ASK_URL, {
|
|
300
311
|
method: "POST",
|
|
301
312
|
headers: {
|
|
302
|
-
Authorization: `Bearer ${
|
|
313
|
+
...(auth.type === "cookies" ? { Cookie: auth.cookies } : { Authorization: `Bearer ${auth.token}` }),
|
|
303
314
|
"Content-Type": "application/json",
|
|
304
315
|
Accept: "text/event-stream",
|
|
305
316
|
Origin: "https://www.perplexity.ai",
|
|
@@ -456,11 +467,11 @@ function applySourceLimit(result: SearchResponse, limit?: number): SearchRespons
|
|
|
456
467
|
export async function searchPerplexity(params: PerplexitySearchParams): Promise<SearchResponse> {
|
|
457
468
|
const auth = await findPerplexityAuth();
|
|
458
469
|
if (!auth) {
|
|
459
|
-
throw new Error("Perplexity auth not found. Set PERPLEXITY_API_KEY or login via OAuth.");
|
|
470
|
+
throw new Error("Perplexity auth not found. Set PERPLEXITY_COOKIES, PERPLEXITY_API_KEY, or login via OAuth.");
|
|
460
471
|
}
|
|
461
472
|
|
|
462
|
-
if (auth.type === "oauth") {
|
|
463
|
-
const oauthResult = await callPerplexityOAuth(auth
|
|
473
|
+
if (auth.type === "oauth" || auth.type === "cookies") {
|
|
474
|
+
const oauthResult = await callPerplexityOAuth(auth, params);
|
|
464
475
|
return applySourceLimit(
|
|
465
476
|
{
|
|
466
477
|
provider: "perplexity",
|