fix(web-search): parsed double-encoded zai results
Decoded the extra JSON string layer returned by Z.AI MCP search and kept structured payloads out of answer text. Added regression coverage for source extraction and plain prose preservation. Fixes #8000
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Z.AI web search dropping sources and exposing raw JSON when MCP responses double-encode content text ([#8000](https://github.com/can1357/oh-my-pi/issues/8000)).
|
||||
|
||||
## [17.2.11] - 2026-08-07
|
||||
|
||||
### Added
|
||||
|
||||
@@ -353,11 +353,20 @@ function parseSearchPayload(rawResult: unknown): {
|
||||
for (const part of content) {
|
||||
const text = isRecord(part) ? asString(part.text) : null;
|
||||
if (!text) continue;
|
||||
textParts.push(text);
|
||||
try {
|
||||
candidates.push(JSON.parse(text));
|
||||
let parsed: unknown = JSON.parse(text);
|
||||
if (typeof parsed === "string") {
|
||||
try {
|
||||
parsed = JSON.parse(parsed);
|
||||
} catch {
|
||||
// The decoded string is answer text rather than another JSON payload.
|
||||
}
|
||||
}
|
||||
candidates.push(parsed);
|
||||
if (getSearchResults(parsed).length === 0) textParts.push(text);
|
||||
} catch {
|
||||
// Not JSON payload; keep as fallback answer text.
|
||||
// Non-JSON content is preserved as answer text.
|
||||
textParts.push(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ interface CapturedRequest {
|
||||
}
|
||||
|
||||
describe("Z.AI web search provider", () => {
|
||||
it("initializes a Streamable HTTP MCP session before calling web_search_prime", async () => {
|
||||
it("initializes a Streamable HTTP MCP session and parses doubly encoded results", async () => {
|
||||
const capturedRequests: CapturedRequest[] = [];
|
||||
const fetchImpl: FetchImpl = (_input, init) => {
|
||||
const request = {
|
||||
@@ -53,16 +53,20 @@ describe("Z.AI web search provider", () => {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: JSON.stringify({
|
||||
search_result: [
|
||||
text: JSON.stringify(
|
||||
JSON.stringify([
|
||||
{
|
||||
title: "Z.AI search result",
|
||||
content: "Search result content",
|
||||
link: "https://example.com/zai",
|
||||
media: "Example",
|
||||
},
|
||||
],
|
||||
}),
|
||||
]),
|
||||
),
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: "Plain prose answer.",
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -107,6 +111,7 @@ describe("Z.AI web search provider", () => {
|
||||
author: "Example",
|
||||
},
|
||||
]);
|
||||
expect(response.answer).toBe("Plain prose answer.");
|
||||
});
|
||||
|
||||
function createMcpFetch(): { fetchImpl: FetchImpl; capturedRequests: CapturedRequest[] } {
|
||||
|
||||
Reference in New Issue
Block a user