{"record":{"id":"4ae05b223b01ecea","repo":"jackwener/OpenCLI","slug":"no-assistant-reply-found-in-qianwen-chat","errorCode":null,"errorMessage":"No assistant reply found in Qianwen chat.","messagePattern":"No assistant reply found in Qianwen chat\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/qwen/ask.js","lineNumber":79,"sourceCode":"\n        // Anchor on the visible transcript BEFORE sending so waitForAnswer can\n        // bind the reply to the newly sent prompt instead of an older answer.\n        const baselineAnchor = await getBaselineChatAnchor(page);\n\n        const send = await sendMessage(page, prompt);\n        if (!send?.ok) {\n            if (await hasLoginGate(page)) throw authRequired();\n            throw new CommandExecutionError(send?.reason || 'Failed to send Qianwen prompt');\n        }\n\n        const result = await waitForAnswer(page, prompt, timeout, baselineAnchor);\n        if (result.status === 'auth_required') throw authRequired();\n        if (result.status === 'timeout') {\n            throw new TimeoutError('qianwen ask', timeout, 'No Qianwen reply observed before timeout. Retry with --timeout increased.');\n        }\n        const assistant = result.assistant;\n        if (!assistant) {\n            throw new CommandExecutionError('No assistant reply found in Qianwen chat.');\n        }\n        const answer = wantMarkdown && assistant.html\n            ? (bubbleHtmlToMarkdown(assistant.html) || assistant.text)\n            : assistant.text;\n        return [\n            { Role: 'User', Text: prompt },\n            { Role: 'Assistant', Text: answer },\n        ];\n    },\n});\n\nasync function getBaselineChatAnchor(page) {\n    const bubbles = await getMessageBubbles(page);\n    const lastBubbleId = bubbles.length ? bubbles[bubbles.length - 1].id : '';\n    let lastAssistantId = '';\n    for (let i = bubbles.length - 1; i >= 0; i -= 1) {\n        if (bubbles[i].role === 'Assistant') {\n            lastAssistantId = bubbles[i].id;","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/qwen/ask.js#L61-L97","documentation":"CommandExecutionError thrown when waitForAnswer finished without a timeout or auth failure but returned no assistant object — the reply could not be located/parsed in the chat DOM.","triggerScenarios":"waitForAnswer returns with result.assistant undefined: the reply bubble selector mismatched, the chat DOM structure changed, the response was an error card instead of an answer, or bubbleHtmlToMarkdown produced no usable text path.","commonSituations":"Qianwen frontend update renaming reply container classes; answer rendered as an error/filtered-content notice; streaming UI state the extractor does not handle; wantMarkdown conversion failing silently leaving empty text.","solutions":["Inspect the page DOM after failure and update the assistant-bubble selector used by waitForAnswer.","Retry without --markdown to rule out HTML->markdown conversion producing empty output.","Check whether Qianwen returned a refusal/error card and adjust prompting.","Upgrade the library if a newer release adapts to the new UI."],"exampleFix":"// before\nconst ans = await qwenAsk(page, { prompt: q, markdown: true });\n// after\nlet ans;\ntry { ans = await qwenAsk(page, { prompt: q, markdown: true }); }\ncatch (e) {\n  if (String(e.message).includes('No assistant reply')) {\n    ans = await qwenAsk(page, { prompt: q, markdown: false });\n  } else throw e;\n}","handlingStrategy":"fallback","validationCode":"// no pre-call check possible; mitigate by disabling markdown conversion path\nconst opts = { prompt, markdown: false };","typeGuard":"function isNoReplyError(e) {\n  return e instanceof CommandExecutionError && e.message.includes('No assistant reply');\n}","tryCatchPattern":"try {\n  ans = await qwenAsk(page, { prompt, markdown: true });\n} catch (e) {\n  if (isNoReplyError(e)) {\n    ans = await qwenAsk(page, { prompt, markdown: false });\n  } else { throw e; }\n}","preventionTips":["Retry without --markdown to isolate conversion issues","Update the library after Qianwen UI changes","Capture a DOM snapshot on failure for selector debugging","Avoid prompting that triggers refusal/error cards"],"tags":["dom","parsing","browser-automation"],"backgroundTag":"dom-structure-changed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}