jackwener/OpenCLI · error · EmptyResultError

No assistant message visible.

Error message

No assistant message visible.

What it means

Thrown by kimi copy-message when the loaded page has no turns with role 'Assistant'. The command filters readKimiTurns output for assistant messages and errors out with EmptyResultError if none exist, since there is nothing to copy.

Source

Thrown at clis/kimi/chat.js:341

    name: 'copy-message',
    access: 'write',
    description: 'Return the text of the last assistant message. Pass --conv <id> to navigate to a specific chat first.',
    domain: KIMI_DOMAIN,
    strategy: Strategy.COOKIE,
    browser: true,
    siteSession: 'persistent',
    navigateBefore: false,
    args: [
        { name: 'conv', required: false, help: 'Chat id or URL (navigates there before reading)' },
        { name: 'click-button', type: 'boolean', default: false, help: 'Also click in-UI Copy button (writes to clipboard)' },
    ],
    columns: CHAT_COLUMNS,
    func: async (page, kwargs) => {
        await maybeNavigateConv(page, kwargs?.conv);
        const turns = await readKimiTurns(page);
        const assistantTurns = turns.filter((t) => t.role === 'Assistant');
        if (!assistantTurns.length) {
            throw new EmptyResultError('kimi copy-message', 'No assistant message visible.');
        }
        const last = assistantTurns[assistantTurns.length - 1];
        if (kwargs?.['click-button'] === true || kwargs?.['click-button'] === 'true') {
            const clickRes = await page.evaluate(clickBySvgNameScript('Copy'));
            if (!clickRes?.ok) throw new CommandExecutionError(clickRes?.reason || 'Copy button not visible', '');
        }
        return [
            { Field: 'Length', Value: String((last.text || '').length) + ' chars' },
            { Field: 'ClipboardClicked', Value: (kwargs?.['click-button'] === true || kwargs?.['click-button'] === 'true') ? 'yes' : 'no' },
            { Field: 'Text', Value: last.text || '' },
        ];
    },
});

// -------- regenerate --------
cli({
    site: 'kimi',
    name: 'regenerate',

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Wait for the assistant response to finish (poll kimi read until an Assistant turn appears), then call copy-message.
  2. Pass the correct `conv` id for a conversation that has replies.
  3. Retry after a short wait if the response is still streaming.

Example fix

// before
await cli('kimi', 'send', { text: 'hi' });
await cli('kimi', 'copy-message'); // may race the reply
// after
await cli('kimi', 'send', { text: 'hi' });
await page.wait(5); // or poll kimi read for an Assistant turn
await cli('kimi', 'copy-message');
Defensive patterns

Strategy: retry

Validate before calling

// only copy after an assistant turn exists
const turns = await cli('kimi', 'read', { conv });
const hasAssistant = turns.some(t => t.Role === 'Assistant');
if (!hasAssistant) await page.wait(5);

Type guard

function hasAssistantTurn(t) { return Array.isArray(t) && t.some(x => x.Role === 'Assistant'); }

Try / catch

try {
  return await cli('kimi', 'copy-message', { conv });
} catch (e) {
  if (/No assistant message visible/.test(e.message)) {
    await page.wait(5);
    return cli('kimi', 'copy-message', { conv });
  }
  throw e;
}

Prevention

When it happens

Trigger: Running copy-message on a conversation where Kimi has not yet replied — user-only conversation, assistant still streaming its first response, or an empty/new-chat page.

Common situations: Calling copy-message immediately after send before the reply arrives; reading the wrong conversation; a page where previous replies were deleted.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/4c1e03e636ed3a25. Report an issue: GitHub.