diff --git a/changelog.d/fixes/14009-perplexity-web-preserve-spaces.md b/changelog.d/fixes/14009-perplexity-web-preserve-spaces.md new file mode 100644 index 0000000000..a27f1d5f23 --- /dev/null +++ b/changelog.d/fixes/14009-perplexity-web-preserve-spaces.md @@ -0,0 +1 @@ +- **fix(providers):** Perplexity Web no longer collapses runs of spaces in non-streaming answers (the path tool mode always takes), which flattened code indentation in `write_file` arguments and plain code blocks; citation markers are still removed with single spacing left behind ([#13968](https://github.com/diegosouzapw/OmniRoute/issues/13968)) diff --git a/open-sse/executors/perplexity-web/protocol.ts b/open-sse/executors/perplexity-web/protocol.ts index 9c8de0f8c0..8c2419f361 100644 --- a/open-sse/executors/perplexity-web/protocol.ts +++ b/open-sse/executors/perplexity-web/protocol.ts @@ -91,12 +91,14 @@ export const THINKING_MAP: Record = { "pplx-grok-4.6": "grok46medium", }; -export const CITATION_RE = /\[\d+\]/g; +// Eats the space before the marker so "text [1] more" cleans to "text more". +// Never squash runs of spaces here: the non-streaming path (tool mode always) +// would flatten code indentation (#13968). +export const CITATION_RE = / ?\[\d+\]/g; export const GROK_TAG_RE = /]*>.*?<\/grok:[^>]*>/gs; export const GROK_SELF_RE = /]*\/>/g; export const XML_DECL_RE = /<[?]xml[^?]*[?]>/g; export const RESPONSE_TAG_RE = /<\/?response\b[^>]*>/gi; -export const MULTI_SPACE = / {2,}/g; export const MULTI_NL = /\n{3,}/g; // ─── Helpers ──────────────────────────────────────────────────────────────── @@ -109,7 +111,6 @@ export function cleanResponse(text: string, strip = true): string { t = t.replace(GROK_SELF_RE, ""); t = t.replace(RESPONSE_TAG_RE, ""); if (strip) { - t = t.replace(MULTI_SPACE, " "); t = t.replace(MULTI_NL, "\n\n"); t = t.trim(); } diff --git a/tests/unit/perplexity-web-preserve-spaces-13968.test.ts b/tests/unit/perplexity-web-preserve-spaces-13968.test.ts new file mode 100644 index 0000000000..9ab672d7ae --- /dev/null +++ b/tests/unit/perplexity-web-preserve-spaces-13968.test.ts @@ -0,0 +1,31 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; + +import { cleanResponse } from "../../open-sse/executors/perplexity-web/protocol.ts"; + +// #13968: the non-streaming path (which tool mode always uses) collapsed every +// run of spaces to one, so code written through perplexity-web lost its +// indentation. Runs of spaces must survive; citation cleanup must still leave +// single spacing behind. + +const PY = ["```python", "def f(x):", " if x:", " return 1", " return 0", "```"].join( + "\n" +); + +test("cleanResponse keeps leading indentation and internal runs of spaces", () => { + assert.equal(cleanResponse(PY), PY); + assert.equal(cleanResponse("a = 1 # aligned comment"), "a = 1 # aligned comment"); +}); + +test("cleanResponse still removes citations without leaving double spaces", () => { + assert.equal(cleanResponse("text [1] more"), "text more"); + assert.equal(cleanResponse("text [1][2] more"), "text more"); + assert.equal(cleanResponse("text [3]."), "text."); + assert.equal(cleanResponse("text[4] more"), "text more"); +}); + +test("cleanResponse trim and blank-line squashing are unchanged", () => { + assert.equal(cleanResponse(" hello "), "hello"); + assert.equal(cleanResponse("a\n\n\n\nb"), "a\n\nb"); + assert.equal(cleanResponse(" keep ", false), " keep "); +});