freechat-deepseek

openclaw browser open https://chat.deepseek.com and login it, then input questions from user's messages, extract response of deepseek chat to reply user.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "freechat-deepseek" with this command: npx skills add qidu/freechat-deepseek

DeepSeek Chat Automation Skill

Automate login with scanning qr code snapshot, input questions from user messages, and extract responses from DeepSeek chat, then reply to user.

Key Feature: Pure browser automation + DOM extraction. No LLM requests or processing - just raw text from the rendered page.

When to Use

USE this skill when:

  • User wants to ask or query on DeepSeek Chat (https://chat.deepseek.com)
  • Sending user questions from messages to DeepSeek Chat
  • Extracting AI responses as raw text (no LLM processing)
  • Browser automation workflows
  • Extract answers from DeepSeek Chat Page with direct output

DON'T use this skill when:

  • Need real-time SSE stream capture (use curl/WebSocket directly)
  • Page uses heavy anti-bot protection
  • Requires complex CAPTCHA solving
  • Need LLM-powered text processing (use Claude API directly)

Requirements

  • Check browser extension with openclaw browser status, get enabled: true
  • Browser tool with profile: "openclaw"
  • No API keys or LLM credits needed

Workflow Overview (6 Steps)

┌─────────────────────────────────────────────────────────────────┐
│  1. Open chat.deepseek.com OR check existing tab                │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  2. Check login status - QR Code needed?                        │
│     - If login form → Take snapshot of login page               │
│     - If chat interface → Already logged in, proceed to Step 3   │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌──────────────────────────────────────────────────────────────────────────────────┐
│  3. Send QR Code to enabled channels (iMessage/WhatsApp/QQBot/Feishu/WeCom/Slack │
│     - Send snapshot to user via imsg                                             │
│     - If WhatsApp is active, send via WhatsApp                                   │
│     - If QQBot is active, send via QQBot, Feishu, WeCom, Slack, etc              │
└─────────────────────────────────┬────────────────────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  4. Wait for login (with timeout & retry loop)                 │
│     - Poll every 5 seconds for login success                   │
│     - If timeout: refresh page, re-snapshot QR, retry send      │
│     - Repeat until logged in successfully                        │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────┐
│  5. Input question and press Enter                              │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  6. Extract response from DOM and reply to user                   │
└─────────────────────────────────────────────────────────────────────────┘

🎯 SIMPLE & RELIABLE RESPONSE EXTRACTION

IMPORTANT FOR AGENTS: Always use this simple extraction function instead of writing complex code. It's tested and reliable.

// SIMPLE & RELIABLE DeepSeek response extraction
// Use this function instead of writing your own extraction code
async function getDeepSeekResponseSimple(tabId) {
  try {
    const response = await browser({
      action: "act",
      kind: "evaluate",
      profile: "openclaw",
      targetId: tabId,
      fn: `(function() {
        // Get all text from the page body
        const allText = document.body.innerText || document.body.textContent || '';
        
        // Split into lines
        const lines = allText.split('\n');
        
        // Filter out system messages and find the response
        const responseLines = [];
        let foundResponse = false;
        
        for (let i = lines.length - 1; i >= 0; i--) {
          const line = lines[i].trim();
          
          // Skip empty lines and system messages
          if (line.length < 20) continue;
          if (line.includes('AI-generated')) continue;
          if (line.includes('Message DeepSeek')) continue;
          if (line.includes('How can I help')) continue;
          if (line.includes('Upload docs')) continue;
          if (line.includes('⌘')) continue;
          
          // This is likely the response
          responseLines.unshift(line);
          foundResponse = true;
        }
        
        // Combine response lines
        if (foundResponse && responseLines.length > 0) {
          return responseLines.join('\n\n').trim();
        }
        
        return 'No response found';
      })()`,
      returnByValue: true
    });
    
    return response;
  } catch (error) {
    console.error("Error extracting response:", error);
    return `Error: ${error.message}`;
  }
}

// Usage example:
// 1. Ask your question
// 2. Wait 10-15 seconds for response
// 3. Call: const answer = await getDeepSeekResponseSimple(tabId);
// 4. Use the answer

Step 1: Open or Reuse Tab

// Try to find existing DeepSeek tab first
const existingTabs = await sessions_list({ /* filter for chat.deepseek.com */ });

if (existingTabs.length > 0) {
  console.log("✅ Reusing existing DeepSeek tab:", existingTabs[0]);
  tabId = existingTabs[0];
} else {
  // Open new tab
  const result = await browser({
    action: "open",
    profile: "openclaw",
    targetUrl: "https://chat.deepseek.com/"
  });
  tabId = result.targetId;
  console.log("✅ Opened new DeepSeek tab:", tabId);
}

// Wait for page to load
await new Promise(r => setTimeout(r, 3000));

Step 2: Check Login Status (QR Code Needed?)

// Check if login required (QR Code scan) or already logged in
await browser({
  action: "snapshot",
  profile: "openclaw",
  targetId: tabId
});

// Evaluate login status
const loginStatus = await browser({
  action: "act",
  kind: "evaluate",
  profile: "openclaw",
  targetId: tabId,
  fn: `{
    const loginForm = document.querySelector('input[type="tel"], input[placeholder*="Phone"]');
    const qrCode = document.querySelector('iframe[src*="wechat"], img[alt*="WeChat"], img[src*="wechat"]');
    const chatInput = document.querySelector('textarea[placeholder*="Message DeepSeek"]');
    const userAvatar = document.querySelector('[class*="avatar"], [class*="user"]');
    
    JSON.stringify({ 
      needLogin: !!(loginForm || qrCode),
      hasChatInput: !!chatInput,
      hasUser: !!userAvatar,
      hasLoginForm: !!loginForm,
      hasQrCode: !!qrCode
    });
  }`,
  returnByValue: true
});

const status = JSON.parse(loginStatus);

if (!status.needLogin && status.hasChatInput) {
  console.log("✅ Already logged in!");
  // Proceed to Step 5 (input question)
} else {
  console.log("⚠️ QR Code login required!");
  // Proceed to Step 3 (send QR code)
}

Login Status Indicators

StatusCheckAction Required
✅ Already Logged InChat input visible + user avatarProceed to Step 5
❌ Need LoginQR Code or login form visibleProceed to Step 3

Step 3: Send QR Code to Enabled Channels

// Navigate to login page explicitly
await browser({
  action: "navigate",
  profile: "openclaw",
  targetId: tabId,
  targetUrl: "https://chat.deepseek.com/sign_in"
});

await new Promise(r => setTimeout(r, 2000));

// Take screenshot of QR Code login page
const screenshotResult = await browser({
  action: "screenshot",
  profile: "openclaw",
  targetId: tabId
});

// Get the screenshot path from the browser tool response
const screenshotPath = screenshotResult.path;

// Get user phone number (configure this in your implementation)
const userPhone = process.env.DEEPSEEK_PHONE || "+1234567890000"; // Configure this

// Try to send via enabled and running channels such as iMessage (most reliable on Mac)
try {
  await exec({
    command: 'imsg send --to "' + userPhone + '" --text "Please scan this QR code with WeChat to login to DeepSeek:" --file "' + screenshotPath + '"'
  });
  console.log("✅ QR Code sent via iMessage");
} catch (e) {
  console.log("⚠️ iMessage failed:", e.message);
}

// Try to send via WhatsApp if available
try {
  await exec({
    command: 'openclaw message send --channel whatsapp --target "' + userPhone + '" -m "Please scan QR code with WeChat to login" --media "' + screenshotPath + '"'
  });
  console.log("✅ QR Code sent via WhatsApp");
} catch (e) {
  console.log("⚠️ WhatsApp not available:", e.message);
}

// Try to send via QQBot (use media tags)
try {
  await exec({
    command: 'openclaw message send --channel qqbot -m "Please scan this QR code with WeChat to login to DeepSeek:\\n<qqimg>' + screenshotPath + '</qqimg>"'
  });
  console.log("✅ QR Code sent via QQBot");
} catch (e) {
  console.log("⚠️ QQBot not available:", e.message);
}

QR Code Sending Priority

Send QR Code to session which is executing this skill firstly. And also send by other avlabile channels:

  1. iMessage (imsg) - Most reliable on Mac (uses userPhone variable)
  2. WhatsApp - If WhatsApp Web is active (uses userPhone variable)
  3. QQBot - If QQ bot is configured (no phone number needed for QQBot)
  4. Signal - If Signal CLI is available (would need phone number configuration)

Step 4: Wait for Login (with Timeout & Retry Loop)

// Poll for login success
let attempts = 0;
const maxAttempts = 24; // 24 * 5 seconds = 2 minutes max
const retryInterval = 5000;

async function checkLoginSuccess() {
  const result = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `{
      const chatInput = document.querySelector('textarea[placeholder*="Message DeepSeek"]');
      const userAvatar = document.querySelector('[class*="avatar"], [class*="user"]');
      { hasChatInput: !!chatInput, hasUser: !!userAvatar };
    }`,
    returnByValue: true
  });
  return JSON.parse(result);
}

while (attempts < maxAttempts) {
  await new Promise(r => setTimeout(r, retryInterval));
  
  const loginResult = await checkLoginSuccess();
  
  if (loginResult.hasChatInput && loginResult.hasUser) {
    console.log("✅ Login successful!");
    break;
  }
  
  attempts++;
  console.log("⏳ Waiting for login... (" + attempts + "/" + maxAttempts + ")");
  
  // If timeout (after 12 attempts = 1 minute), refresh and retry
  if (attempts === 12) {
    console.log("⏰ Timeout, refreshing QR code...");
    
    await browser({
      action: "navigate",
      profile: "openclaw",
      targetId: tabId,
      targetUrl: "https://chat.deepseek.com/sign_in"
    });
    
    await new Promise(r => setTimeout(r, 3000));
    
    // Re-take screenshot and send again
    await browser({
      action: "screenshot",
      profile: "openclaw",
      targetId: tabId
    });
    
    // Re-take screenshot and send again
    const newScreenshotResult = await browser({
      action: "screenshot",
      profile: "openclaw",
      targetId: tabId
    });
    const newScreenshotPath = newScreenshotResult.path;
    
    // Re-send QR code
    try {
      await exec({
        command: 'imsg send --to "' + userPhone + '" --text "QR code refreshed - please scan again with WeChat" --file "' + newScreenshotPath + '"'
      });
    } catch (e) {}
  }
}

if (attempts >= maxAttempts) {
  throw new Error("Login timeout - user did not complete QR scan in time");
}

Login Timeout Strategy

AttemptTimeAction
1-120-60sPoll every 5s, wait for scan
1260sRefresh page, re-send QR code
13-2465-120sContinue polling
24120sFail with timeout error

Step 5: Input Question and Press Enter

// Ensure we're on chat page
await browser({
  action: "navigate",
  profile: "openclaw",
  targetId: tabId,
  targetUrl: "https://chat.deepseek.com/"
});

await new Promise(r => setTimeout(r, 2000));

// Take snapshot to get fresh refs
await browser({
  action: "snapshot",
  profile: "openclaw",
  targetId: tabId
});

// Type message into input box (use textbox ref from snapshot)
await browser({
  action: "act",
  kind: "type",
  profile: "openclaw",
  targetId: tabId,
  ref: "e102", // Get from snapshot - textarea ref
  text: "Your question here"
});

console.log("✅ Text typed into input box");

// Press Enter to submit
await browser({
  action: "act",
  kind: "press",
  profile: "openclaw",
  targetId: tabId,
  key: "Enter"
});

console.log("✅ Enter key pressed");

Step 6: Extract Response from DOM

NEVER send raw html content with <tool_call> to user session.

// Wait for response to generate (8-15 seconds depending on complexity)
await new Promise(r => setTimeout(r, 10000));

// Extract assistant response from page body
const response = await browser({
  action: "act",
  kind: "evaluate",
  profile: "openclaw",
  targetId: tabId,
  fn: `{
    // Get all paragraph elements from the entire page body
    const body = document.body;
    const paras = Array.from(body.querySelectorAll('p'));
    
    // Filter to find assistant messages (not user messages, not system text)
    const assistantMsgs = paras.filter(p => {
      const text = p.innerText || '';
      const parent = p.parentElement;
      
      // Exclude system messages and user messages
      return text.length > 15 && 
             !text.includes('AI-generated') &&
             !text.includes('Upload docs') &&
             !text.includes('How can I help') &&
             !text.includes('⌘') &&
             parent && !parent.closest('header') &&
             parent && !parent.closest('footer');
    });
    
    // Get the most recent assistant message
    const lastResponse = assistantMsgs.length > 0 
      ? assistantMsgs[assistantMsgs.length - 1].innerText 
      : 'No response found';
    
    // Clean up the response
    return lastResponse.trim();
  }`,
  returnByValue: true
});

console.log("✅ DeepSeek Response:", response);

Response Extraction Strategy

ElementStrategy
Containerdocument.body
Message type<p> tags
Filter outAI-generated, Upload docs, Help text, Keyboard shortcuts
GetLast matching <p> from body

Complete Example: Full Workflow

// ============ DEEPSEEK CHAT AUTOMATION ============

const profile = "openclaw";
// Get user phone number from USER.md or configuration
// Example: Read from USER.md or use environment variable
const userPhone = process.env.DEEPSEEK_PHONE || "+1234567890000"; // Default fallback - configure this

// Step 1: Open or reuse tab
const openResult = await browser({
  action: "open",
  profile: profile,
  targetUrl: "https://chat.deepseek.com/"
});
const tabId = openResult.targetId;

await new Promise(r => setTimeout(r, 3000));

// Step 2: Check login status
await browser({ action: "snapshot", profile, targetId: tabId });
const loginCheck = await browser({
  action: "act",
  kind: "evaluate",
  profile,
  targetId: tabId,
  fn: `{
    const chatInput = document.querySelector('textarea[placeholder*="Message DeepSeek"]');
    const qrCode = document.querySelector('img[src*="wechat"]');
    { needLogin: !chatInput, hasQrCode: !!qrCode };
  }`,
  returnByValue: true
});

const status = JSON.parse(loginCheck);

if (!status.needLogin) {
  console.log("Already logged in!");
} else {
  // Step 3: Send QR code
  await browser({ action: "navigate", profile, targetId: tabId, targetUrl: "https://chat.deepseek.com/sign_in" });
  await new Promise(r => setTimeout(r, 2000));
  const screenshotResult = await browser({ action: "screenshot", profile, targetId: tabId });
  
  const screenshotPath = screenshotResult.path;
  
  // Send via iMessage
  await exec({
    command: 'imsg send --to "' + userPhone + '" --text "Please scan QR code to login to DeepSeek" --file "' + screenshotPath + '"'
  });
  
  // Step 4: Wait for login with retry
  let attempts = 0;
  while (attempts < 24) {
    await new Promise(r => setTimeout(r, 5000));
    const result = await browser({
      action: "act",
      kind: "evaluate",
      profile,
      targetId: tabId,
      fn: `{
        const chatInput = document.querySelector('textarea[placeholder*="Message DeepSeek"]');
        !!chatInput;
      }`,
      returnByValue: true
    });
    
    if (result === 'true') {
      console.log("Login successful!");
      break;
    }
    
    attempts++;
    
    // Refresh QR every 60 seconds
    if (attempts === 12) {
      await browser({ action: "navigate", profile, targetId: tabId, targetUrl: "https://chat.deepseek.com/sign_in" });
      await new Promise(r => setTimeout(r, 3000));
      const newScreenshotResult = await browser({ action: "screenshot", profile, targetId: tabId });
      const newScreenshotPath = newScreenshotResult.path;
      await exec({
        command: 'imsg send --to "' + userPhone + '" --text "QR refreshed - please scan again" --file "' + newScreenshotPath + '"'
      });
    }
  }
}

// Step 5: Input question
await browser({ action: "navigate", profile, targetId: tabId, targetUrl: "https://chat.deepseek.com/" });
await new Promise(r => setTimeout(r, 2000));
await browser({ action: "snapshot", profile, targetId: tabId });

await browser({
  action: "act",
  kind: "type",
  profile,
  targetId: tabId,
  ref: "e102", // From snapshot
  text: "What is the capital of France?"
});

await browser({ action: "act", kind: "press", profile, targetId: tabId, key: "Enter" });

// Step 6: Extract response
await new Promise(r => setTimeout(r, 10000));

// Robust response extraction
const response = await browser({
  action: "act",
  kind: "evaluate",
  profile,
  targetId: tabId,
  fn: `(function() {
    // Get all paragraph elements
    const paragraphs = Array.from(document.querySelectorAll('p'));
    
    // Filter to find assistant responses
    const assistantResponses = paragraphs.filter(p => {
      const text = p.innerText || p.textContent || '';
      return text.length > 20 && 
             !text.includes('AI-generated') &&
             !text.includes('Upload docs') &&
             !text.includes('How can I help') &&
             !text.includes('⌘');
    });
    
    // Get the most recent (last) response
    if (assistantResponses.length > 0) {
      return assistantResponses[assistantResponses.length - 1].innerText.trim();
    }
    
    // Fallback: try to find any substantial text
    const bodyText = document.body.innerText || document.body.textContent || '';
    const lines = bodyText.split('\n').filter(line => 
      line.trim().length > 50 && 
      !line.includes('AI-generated') &&
      !line.includes('How can I help')
    );
    
    return lines.length > 0 ? lines[lines.length - 1].trim() : 'No response found';
  })()`,
  returnByValue: true
});

console.log("Response:", response);
// Reply to user with response

Common Selectors

ElementSelector
Chat inputtextarea[placeholder*="Message DeepSeek"]
Send (Enter)Press Enter key
QR Codeimg[src*="wechat"], iframe[src*="wechat"]
User avatar[class*="avatar"], [class*="user"]
Response contentLast <p> in document.body (filtered)

Configuration

Phone Number Configuration

The user's phone number can be configured in several ways:

  1. Environment Variable: Set DEEPSEEK_PHONE environment variable

    export DEEPSEEK_PHONE="+1234567890000"
    
  2. USER.md: Add phone number to USER.md file

    # USER.md
    Phone: +1234567890000
    
  3. Configuration File: Add to OpenClaw configuration

    // In your implementation code
    const userPhone = config.userPhone || process.env.DEEPSEEK_PHONE || "+1234567890000";
    

QR Code Path Handling

The screenshot path is automatically returned by the browser tool's screenshot action:

const screenshotResult = await browser({ action: "screenshot", profile: "openclaw", targetId: tabId });
const screenshotPath = screenshotResult.path; // Use the actual path from result

Important: Never assume a fixed path like /Users/chris/.openclaw/media/browser/<uuid>.jpg. Always use the path returned by the browser tool.


Limitations

  • Rate Limiting: DeepSeek may block requests (429 errors)
  • Event Validation: Some buttons need real user events (use kind: "press" not JS dispatchEvent)
  • Login Verification: QR Code scan requires user interaction
  • No API Access: Direct API requires bypassing WAF
  • No Files Uploading: DO NOT upload files to chat.deepseek.com
  • No LLM Processing: Extract raw text only
  • Login Timeout: Maximum 2 minutes for QR scan

Troubleshooting

IssueSolution
Input not foundRefresh page, take new snapshot
Enter not workingUse browser act kind="press" with key="Enter"
❌ Enter via JS dispatchEvent doesn't workDeepSeek uses React/event validation - must use kind: "press" with key: "Enter" instead
Response not foundWait longer, check page rendering
QR Code timeoutAutomatically refreshes and re-sends
Login with phoneDO NOT ask and input phone number
All channels failAsk user to check browser tab manually

🆕 Optimized: "Try Again with Fresh Question" Workflow

When a user wants to retry with a fresh question (e.g., after getting "Sorry, that's beyond my current scope"), use this optimized workflow:

Option 1: Start Fresh Chat (Recommended for unsatisfactory responses)

// Function to start a fresh chat session
async function startFreshChat(tabId) {
  // Navigate to main page to ensure clean state
  await browser({
    action: "navigate",
    profile: "openclaw",
    targetId: tabId,
    targetUrl: "https://chat.deepseek.com/"
  });
  
  await new Promise(r => setTimeout(r, 2000));
  
  // Take snapshot to get fresh refs
  await browser({
    action: "snapshot",
    profile: "openclaw",
    targetId: tabId
  });
  
  // Check if we're on a fresh chat page
  const status = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      const welcomeMsg = document.querySelector('img[alt*="DeepSeek"], img[src*="deepseek"]');
      const chatInput = document.querySelector('textarea[placeholder*="Message DeepSeek"]');
      const previousChat = document.querySelector('[class*="message"]');
      
      return JSON.stringify({
        isFresh: !!welcomeMsg && !!chatInput && !previousChat,
        hasWelcome: !!welcomeMsg,
        hasInput: !!chatInput,
        hasPreviousChat: !!previousChat
      });
    })()`,
    returnByValue: true
  });
  
  const statusObj = JSON.parse(status);
  
  if (!statusObj.isFresh) {
    // Click "New chat" in sidebar (more reliable than top button)
    const sidebarResult = await browser({
      action: "act",
      kind: "evaluate",
      profile: "openclaw",
      targetId: tabId,
      fn: `(function() {
        // Find "New chat" link in sidebar
        const sidebarLinks = Array.from(document.querySelectorAll('a'));
        const newChatLink = sidebarLinks.find(link => 
          link.innerText.includes('New chat') || 
          link.textContent.includes('新聊天') ||
          (link.querySelector('div') && link.querySelector('div').innerText.includes('New chat'))
        );
        
        if (newChatLink) {
          newChatLink.click();
          return true;
        }
        return false;
      })()`,
      returnByValue: true
    });
    
    if (!sidebarResult) {
      // Fallback: use keyboard shortcut Cmd+J (⌘J)
      await browser({
        action: "act",
        kind: "press",
        profile: "openclaw",
        targetId: tabId,
        key: "Meta",  // Command key on Mac
        modifiers: ["Meta"]
      });
      
      await new Promise(r => setTimeout(r, 100));
      
      await browser({
        action: "act",
        kind: "type",
        profile: "openclaw",
        targetId: tabId,
        text: "j"
      });
      
      await new Promise(r => setTimeout(r, 100));
      
      await browser({
        action: "act",
        kind: "press",
        profile: "openclaw",
        targetId: tabId,
        key: "Meta",
        modifiers: []
      });
    }
    
    await new Promise(r => setTimeout(r, 2000));
  }
  
  return true;
}

Option 2: Continue in Same Chat (if context is needed)

// Function to continue in current chat but clear previous question
async function continueInCurrentChat(tabId, newQuestion) {
  // Just type the new question directly
  await browser({
    action: "snapshot",
    profile: "openclaw",
    targetId: tabId
  });
  
  // Find and focus the input
  const inputFound = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      const input = document.querySelector('textarea[placeholder*="Message DeepSeek"], input[placeholder*="Message DeepSeek"]');
      if (input) {
        input.focus();
        input.value = '';
        return true;
      }
      return false;
    })()`,
    returnByValue: true
  });
  
  if (!inputFound) {
    throw new Error("Chat input not found");
  }
  
  // Type the new question
  await browser({
    action: "act",
    kind: "type",
    profile: "openclaw",
    targetId: tabId,
    ref: "e102", // Get from snapshot - adjust as needed
    text: newQuestion
  });
  
  // Submit
  await browser({
    action: "act",
    kind: "press",
    profile: "openclaw",
    targetId: tabId,
    key: "Enter"
  });
  
  return true;
}

🐛 Common Errors and Fixes

Error: SyntaxError in JavaScript Evaluation

IMPORTANT: Never copy error examples! Always use the working functions provided below.

Common JavaScript syntax errors to avoid:

  • document.querySelecto rAll('p') (space in function name)

  • document.querySelectorAll('p') (correct)

  • split('\\n') (double backslashes)

  • split('\n') (single backslash)

  • ❌ Missing return statement in evaluate functions

  • ✅ Always include return statement

Robust Response Extraction Function

Here's a corrected and more robust version:

// Robust response extraction function
async function extractDeepSeekResponse(tabId) {
  try {
    const response = await browser({
      action: "act",
      kind: "evaluate",
      profile: "openclaw",
      targetId: tabId,
      fn: `(function() {
        // Find the most recent assistant response
        const paragraphs = Array.from(document.querySelectorAll('p'));
        
        // Filter out system messages and short texts
        const assistantParagraphs = paragraphs.filter(p => {
          const text = p.innerText || p.textContent || '';
          const parent = p.parentElement;
          const isSystemMessage = 
            text.includes('AI-generated') ||
            text.includes('Upload docs') ||
            text.includes('How can I help') ||
            text.includes('⌘') ||
            text.includes('We are asked:') ||
            text.length < 20;
          
          // Also check if it's in a response container (not in input area)
          const isInInputArea = parent && (
            parent.closest('textarea') || 
            parent.closest('input') ||
            parent.closest('[class*="input"]') ||
            parent.closest('[class*="message-input"]')
          );
          
          return !isSystemMessage && !isInInputArea && text.trim().length > 0;
        });
        
        // Get the last assistant response
        const lastResponse = assistantParagraphs[assistantParagraphs.length - 1];
        if (!lastResponse) return 'No response found';
        
        // Try to get the full response container
        let responseContainer = lastResponse.closest('div[class*="message"], div[class*="response"], div[class*="assistant"]');
        if (!responseContainer) {
          responseContainer = lastResponse.closest('div');
        }
        
        if (responseContainer) {
          // Get all text content from the response container
          const allText = responseContainer.innerText || responseContainer.textContent || '';
          // Clean up the text - use single backslashes in regex
          return allText
            .replace(/\s+/g, ' ')
            .replace(/\n\s*\n/g, '\n\n')
            .trim();
        }
        
        // Fallback to just the paragraph text
        return lastResponse.innerText || lastResponse.textContent || '';
      })()`,
      returnByValue: true
    });
    
    return response;
  } catch (error) {
    console.error("Error extracting response:", error);
    
    // Fallback: try simpler extraction
    const fallbackResponse = await browser({
      action: "act",
      kind: "evaluate",
      profile: "openclaw",
      targetId: tabId,
      fn: `(function() {
        // Simple fallback: get all text on page and find the last substantial block
        const allText = document.body.innerText || document.body.textContent || '';
        const lines = allText.split('\n').filter(line => 
          line.trim().length > 50 && 
          !line.includes('AI-generated') &&
          !line.includes('How can I help')
        );
        
        return lines.length > 0 ? lines[lines.length - 1].trim() : 'No response found';
      })()`,
      returnByValue: true
    });
    
    return fallbackResponse;
  }
}

// Usage:
// const answer = await extractDeepSeekResponse(tabId);

Common JavaScript Errors to Avoid

IMPORTANT: Always copy from working examples, not error examples!

Common mistakes:

  • Typos in function names: querySelectorAll not querySelecto rAll
  • Spaces in variable names: assistantParagraphs not assistantPar agraphs
  • Incorrect selectors: Use closest('div') not closest('generic')
  • Case sensitivity: returnByValue: true not returnByValue: True
  • Missing semicolons: Always end statements properly

Fix: "No response found" Error

If you're getting "No response found" or "failed to extract response", DeepSeek's page structure has likely changed. Use this more robust extraction method:

// ULTRA-ROBUST response extraction - tries multiple approaches
async function extractDeepSeekResponse(tabId) {
  const response = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      // Helper: check if text is a system message
      function isSystemText(text) {
        const systemPatterns = [
          'AI-generated', 'Upload docs', 'How can I help', '⌘',
          'We are asked:', 'deepseek', 'Sign in', '登录',
          'Message DeepSeek', 'keyboard', 'shortcut'
        ];
        return systemPatterns.some(p => text.includes(p));
      }

      // Approach 1: Try finding message containers
      const messageDivs = document.querySelectorAll('div[class*="message"], div[class*="response"], div[class*="content"]');
      let allTexts = [];

      messageDivs.forEach(div => {
        const text = div.innerText || div.textContent || '';
        if (text.length > 30 && !isSystemText(text)) {
          allTexts.push(text.trim());
        }
      });

      // If we found messages in containers, return the last one
      if (allTexts.length > 0) {
        return allTexts[allTexts.length - 1];
      }

      // Approach 2: Try all <p> tags with relaxed filtering
      const paragraphs = document.querySelectorAll('p');
      const validParagraphs = [];
      paragraphs.forEach(p => {
        const text = p.innerText || p.textContent || '';
        if (text.length > 20 && !isSystemText(text)) {
          validParagraphs.push(text.trim());
        }
      });

      if (validParagraphs.length > 0) {
        return validParagraphs[validParagraphs.length - 1];
      }

      // Approach 3: Try <div> tags (newer DeepSeek structure)
      const divs = document.querySelectorAll('div');
      const validDivs = [];
      divs.forEach(div => {
        const text = div.innerText || div.textContent || '';
        // Look for substantial text blocks in the main content area
        if (text.length > 100 && !isSystemText(text) && !div.closest('header') && !div.closest('footer') && !div.closest('nav')) {
          validDivs.push(text.trim());
        }
      });

      if (validDivs.length > 0) {
        return validDivs[validDivs.length - 1];
      }

      // Approach 4: Fallback to full page body text
      const bodyText = document.body.innerText || document.body.textContent || '';
      const lines = bodyText.split('\n').filter(line =>
        line.trim().length > 50 && !isSystemText(line)
      );

      if (lines.length > 0) {
        return lines[lines.length - 1].trim();
      }

      // Last resort: return debug info
      return 'No response found - page may be loading or have unexpected structure';
    })()`,
    returnByValue: true
  });

  console.log("Extracted response:", response.substring(0, 200) + "...");
  return response;
}

Debugging Tips

// Add debug logging to browser evaluate functions
const debugInfo = await browser({
  action: "act",
  kind: "evaluate",
  profile: "openclaw",
  targetId: tabId,
  fn: `(function() {
    // Debug: log what we find
    const paragraphs = document.querySelectorAll('p');
    console.log('Found', paragraphs.length, 'paragraphs');

    for (let i = 0; i < Math.min(paragraphs.length, 5); i++) {
      console.log('Paragraph', i, ':', paragraphs[i].innerText.substring(0, 100));
    }
    
    return JSON.stringify({
      paragraphCount: paragraphs.length,
      sampleTexts: Array.from(paragraphs).slice(0, 3).map(p => p.innerText.substring(0, 50))
    });
  })()`,
  returnByValue: true
});

console.log("Debug info:", debugInfo);

🛠️ Working Implementation Guide

Always Use These Pre-tested Functions

Instead of writing your own extraction code, always use these pre-tested functions:

// SIMPLE & RELIABLE extraction function
async function extractDeepSeekResponseSimple(tabId) {
  const response = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      // Get all text from the page
      const allText = document.body.innerText || document.body.textContent || '';
      
      // Split into lines and filter out system messages
      const lines = allText.split('\n').filter(line => {
        const trimmed = line.trim();
        return trimmed.length > 50 && 
               !trimmed.includes('AI-generated') &&
               !trimmed.includes('Message DeepSeek') &&
               !trimmed.includes('How can I help') &&
               !trimmed.includes('Upload docs');
      });
      
      // Return the last substantial line (most likely the response)
      return lines.length > 0 ? lines[lines.length - 1].trim() : 'No response found';
    })()`,
    returnByValue: true
  });
  
  return response;
}

// Usage:
// const answer = await extractDeepSeekResponseSimple(tabId);

Key Improvements in Optimized Workflow:

  1. Robust "New Chat" Detection: Uses semantic search for "New chat" text in sidebar links
  2. Fallback Mechanisms: Keyboard shortcut (Cmd+J) if sidebar link not found
  3. State Verification: Checks if we're already on a fresh chat page
  4. Better Response Extraction: Filters out system messages and thought processes
  5. Error Handling: Graceful fallbacks for missing elements
  6. Clear Documentation: Explains when to use fresh chat vs continue in same chat

When to Use Which Approach:

ScenarioRecommended ApproachWhy
Previous response was "Sorry, that's beyond my current scope"Start Fresh ChatDeepSeek might be in a restricted mode; fresh chat resets context
Want to ask unrelated follow-upStart Fresh ChatAvoids confusing the AI with previous context
Continuing same topic with refined questionContinue in Current ChatMaintains context for better responses
Previous response was good but need clarificationContinue in Current ChatAI can reference previous answer

Common Pitfalls Fixed:

  1. ❌ WRONG: Clicking ref=e306 (was a share button, not new chat)
  2. ✅ CORRECT: Clicking "New chat" link in sidebar or using Cmd+J
  3. ❌ WRONG: Assuming input ref is always e102
  4. ✅ CORRECT: Using snapshot to get fresh refs each time
  5. ❌ WRONG: Extracting all paragraphs including system messages
  6. ✅ CORRECT: Filtering out AI-generated disclaimers and thought processes

⚠️ Important Note About Element References:

Never rely on fixed ref IDs like e306, e102, etc. These IDs are:

  • Generated dynamically by the browser snapshot tool
  • Can change between snapshots or page reloads
  • Different for each user and session

Always use semantic selectors or get fresh refs from snapshot:

🧠 DeepThink Mode Optimization

The DeepThink button (labeled "DeepThink" to the left of the "Search" button) enables enhanced reasoning mode. When activated, DeepSeek provides more detailed, step-by-step responses.

How to Enable DeepThink Mode

// Function to toggle DeepThink mode
async function toggleDeepThinkMode(tabId, enable = true) {
  await browser({
    action: "snapshot",
    profile: "openclaw",
    targetId: tabId
  });
  
  // Check current DeepThink state
  const currentState = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      const deepThinkBtn = document.querySelector('button[aria-label*="DeepThink"], button:has(> div:contains("DeepThink"))');
      const searchBtn = document.querySelector('button[aria-label*="Search"], button:has(> div:contains("Search"))');
      
      return JSON.stringify({
        hasDeepThink: !!deepThinkBtn,
        hasSearch: !!searchBtn,
        deepThinkActive: deepThinkBtn ? deepThinkBtn.getAttribute('aria-pressed') === 'true' || 
                                        deepThinkBtn.classList.contains('active') || 
                                        deepThinkBtn.getAttribute('data-active') === 'true' : false,
        deepThinkText: deepThinkBtn ? deepThinkBtn.innerText || deepThinkBtn.textContent : '',
        searchText: searchBtn ? searchBtn.innerText || searchBtn.textContent : ''
      });
    })()`,
    returnByValue: true
  });
  
  const state = JSON.parse(currentState);
  console.log("DeepThink state:", state);
  
  // If we want DeepThink enabled but it's not active
  if (enable && state.hasDeepThink && !state.deepThinkActive) {
    console.log("Enabling DeepThink mode...");
    
    // Click the DeepThink button
    const clicked = await browser({
      action: "act",
      kind: "evaluate",
      profile: "openclaw",
      targetId: tabId,
      fn: `(function() {
        // Find DeepThink button by text content
        const buttons = Array.from(document.querySelectorAll('button'));
        const deepThinkBtn = buttons.find(btn => 
          btn.innerText.includes('DeepThink') || 
          btn.textContent.includes('DeepThink') ||
          (btn.querySelector('div') && btn.querySelector('div').innerText.includes('DeepThink'))
        );
        
        if (deepThinkBtn) {
          deepThinkBtn.click();
          return true;
        }
        
        // Alternative: Find button near search button
        const searchBtn = buttons.find(btn => 
          btn.innerText.includes('Search') || 
          btn.textContent.includes('Search')
        );
        
        if (searchBtn && searchBtn.previousElementSibling) {
          searchBtn.previousElementSibling.click();
          return true;
        }
        
        return false;
      })()`,
      returnByValue: true
    });
    
    if (clicked) {
      console.log("DeepThink mode enabled");
      await new Promise(r => setTimeout(r, 1000)); // Wait for UI update
      return true;
    }
  }
  
  // If we want DeepThink disabled but it's active
  if (!enable && state.hasDeepThink && state.deepThinkActive) {
    console.log("Disabling DeepThink mode...");
    
    // Click the DeepThink button again to toggle off
    const clicked = await browser({
      action: "act",
      kind: "evaluate",
      profile: "openclaw",
      targetId: tabId,
      fn: `(function() {
        const buttons = Array.from(document.querySelectorAll('button'));
        const deepThinkBtn = buttons.find(btn => 
          btn.innerText.includes('DeepThink') || 
          btn.textContent.includes('DeepThink')
        );
        
        if (deepThinkBtn) {
          deepThinkBtn.click();
          return true;
        }
        return false;
      })()`,
      returnByValue: true
    });
    
    if (clicked) {
      console.log("DeepThink mode disabled");
      await new Promise(r => setTimeout(r, 1000));
      return true;
    }
  }
  
  return false;
}

Complete Workflow with DeepThink Mode

// Ask a question with DeepThink mode enabled
async function askWithDeepThink(tabId, question) {
  console.log("Asking question with DeepThink mode...");
  
  // Enable DeepThink mode
  await toggleDeepThinkMode(tabId, true);
  
  // Wait for UI to update
  await new Promise(r => setTimeout(r, 1000));
  
  // Take fresh snapshot
  await browser({
    action: "snapshot",
    profile: "openclaw",
    targetId: tabId
  });
  
  // Find and focus input
  const inputFound = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      const input = document.querySelector('textarea[placeholder*="Message DeepSeek"], input[placeholder*="Message DeepSeek"]');
      if (input) {
        input.focus();
        input.value = '';
        return true;
      }
      return false;
    })()`,
    returnByValue: true
  });
  
  if (!inputFound) {
    throw new Error("Chat input not found");
  }
  
  // Type the question
  await browser({
    action: "act",
    kind: "type",
    profile: "openclaw",
    targetId: tabId,
    text: question
  });
  
  // Submit
  await browser({
    action: "act",
    kind: "press",
    profile: "openclaw",
    targetId: tabId,
    key: "Enter"
  });
  
  // Wait longer for DeepThink response (it thinks before answering)
  console.log("Waiting for DeepThink response (may take 10-15 seconds)...");
  await new Promise(r => setTimeout(r, 15000));
  
  // Extract response
  const response = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      // Get all paragraph elements
      const paras = Array.from(document.querySelectorAll('p'));
      
      // Filter to find assistant responses (including DeepThink reasoning)
      const assistantResponses = paras.filter(p => {
        const text = p.innerText || '';
        return text.length > 20 && 
               !text.includes('AI-generated') &&
               !text.includes('Upload docs') &&
               !text.includes('How can I help') &&
               !text.includes('⌘');
      });
      
      // Get the most recent (last) response
      return assistantResponses.length > 0 
        ? assistantResponses[assistantResponses.length - 1].innerText.trim()
        : 'No response found';
    })()`,
    returnByValue: true
  });
  
  console.log("DeepThink response received");
  return response;
}

// Example usage:
// const deepThinkResponse = await askWithDeepThink(tabId, "Solve: 2x + 5 = 15");

When to Use DeepThink Mode

Use CaseRecommended ModeWhy
Math problems, logic puzzlesDeepThink ONProvides step-by-step reasoning
Code debugging, algorithm designDeepThink ONShows thought process and analysis
Simple factual questionsDeepThink OFFFaster response, no need for reasoning
Creative writing, brainstormingDeepThink ONMore thoughtful, structured responses
Quick information lookupDeepThink OFFFaster, more concise answers

DeepThink Button Identification Strategies

The DeepThink button can be identified in several ways:

  1. By text content: Button containing "DeepThink"
  2. By position: Button immediately left of "Search" button
  3. By aria-label: Button with aria-label containing "DeepThink"
  4. By active state: When enabled, has [active] attribute or aria-pressed="true"
// Multiple strategies for finding DeepThink button
function findDeepThinkButton() {
  // Strategy 1: By text content
  const byText = document.querySelector('button:has(> div:contains("DeepThink"))');
  if (byText) return byText;
  
  // Strategy 2: By aria-label
  const byAria = document.querySelector('button[aria-label*="DeepThink"]');
  if (byAria) return byAria;
  
  // Strategy 3: Relative to Search button
  const searchBtn = document.querySelector('button:has(> div:contains("Search"))');
  if (searchBtn && searchBtn.previousElementSibling) {
    return searchBtn.previousElementSibling;
  }
  
  // Strategy 4: By class names (may change)
  const byClass = document.querySelector('button[class*="deepthink"], button[class*="DeepThink"]');
  if (byClass) return byClass;
  
  return null;
}

Toggle Between Modes

// Toggle between DeepThink and regular mode
async function toggleResponseMode(tabId) {
  const currentState = await browser({
    action: "act",
    kind: "evaluate",
    profile: "openclaw",
    targetId: tabId,
    fn: `(function() {
      const btn = document.querySelector('button[aria-label*="DeepThink"], button:has(> div:contains("DeepThink"))');
      return btn ? (btn.getAttribute('aria-pressed') === 'true' || btn.classList.contains('active')) : false;
    })()`,
    returnByValue: true
  });
  
  const isActive = currentState === 'true';
  console.log(`DeepThink is currently ${isActive ? 'active' : 'inactive'}`);
  
  // Toggle the button
  await toggleDeepThinkMode(tabId, !isActive);
  
  return !isActive;
}

// Usage: const newState = await toggleResponseMode(tabId);
// Returns true if DeepThink is now active, false if regular mode
// ❌ WRONG - Hardcoded ref IDs
await browser({ action: "act", kind: "click", ref: "e306" });

// ✅ CORRECT - Semantic selection
await browser({ action: "act", kind: "evaluate", fn: `(function() {
  const newChatLink = document.querySelector('a[href*="/a/chat"]');
  if (newChatLink && newChatLink.innerText.includes('New chat')) {
    newChatLink.click();
    return true;
  }
  return false;
})()` });

// ✅ CORRECT - Get ref from snapshot
// First take snapshot, then use ref from the snapshot response
const snapshot = await browser({ action: "snapshot", targetId: tabId });
// Parse snapshot to find "New chat" element ref
const newChatRef = findRefByText(snapshot, "New chat");
await browser({ action: "act", kind: "click", ref: newChatRef });

The user's original attempt (<tool_call><function=browser><action>act</action><profile>openclaw</profile><targetId>00AA2439B0832C440F6EDAF46A34029F</targetId><kind>click</kind><ref>e306</ref></function></tool_call>) failed because:

  • ref=e306 was not a "New chat" button (it was likely a share/export button)
  • The correct "New chat" element was ref=e292 in sidebar or ref=e35 after reload ...but these refs are not reliable either!

Always use semantic content-based selection instead of ref IDs.

Why dispatchEvent Doesn't Work

DeepSeek's chat input is built with React and validates that keyboard events come from real user interactions. Using JavaScript's dispatchEvent() to simulate key presses will silently fail:

// ❌ WRONG - This doesn't work!
const input = document.querySelector('textarea[placeholder*="Message DeepSeek"]');
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
input.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' }));

// ✅ CORRECT - Use browser press action
await browser({
  action: "act",
  kind: "press",
  profile: "openclaw",
  targetId: tabId,
  key: "Enter"
});

The press action sends a real key event through the browser automation layer, which passes DeepSeek's event validation.


🎯 Best Practices & Recommendations

Based on analysis of common failures and successful implementations, follow these best practices:

1. Response Extraction Best Practices

✅ DO: Use the Simple Extraction Function

// ALWAYS use this simple function - it's tested and reliable
const response = await getDeepSeekResponseSimple(tabId);

// Only use complex functions if simple one fails
if (response.includes('No response found') || response.includes('Error:')) {
  // Try robust version as fallback
  const response = await extractDeepSeekResponse(tabId);
}

✅ DO: Add Error Handling

try {
  const response = await extractDeepSeekResponse(tabId);
  console.log("Success:", response);
} catch (error) {
  console.error("Extraction failed:", error);
  // Implement fallback strategy
}

✅ DO: Increase Wait Times for Complex Responses

// Simple questions: 10 seconds
await new Promise(r => setTimeout(r, 10000));

// Complex questions or DeepThink mode: 15-20 seconds  
await new Promise(r => setTimeout(r, 15000));

2. Element Selection Best Practices

✅ DO: Use Semantic Selectors

// Find elements by content, not hardcoded refs
const newChatLink = document.querySelector('a[href*="/a/chat"]');
if (newChatLink && newChatLink.innerText.includes('New chat')) {
  newChatLink.click();
}

✅ DO: Get Fresh Refs from Snapshots

// Take snapshot to get current element references
const snapshot = await browser({ action: "snapshot", targetId: tabId });
// Parse snapshot to find elements dynamically

❌ DON'T: Use Hardcoded Ref IDs

// ❌ WRONG - These change dynamically!
await browser({ action: "act", kind: "click", ref: "e306" });
await browser({ action: "act", kind: "click", ref: "e102" });

3. JavaScript Code Quality

✅ DO: Use Correct Regex Patterns

// ❌ WRONG - Double backslashes
.replace(/\\s+/g, ' ')
.split('\\n')

// ✅ CORRECT - Single backslashes  
.replace(/\s+/g, ' ')
.split('\n')

✅ DO: Avoid Optional Chaining in Older Environments

// ❌ WRONG - Might not be supported
msgs[msgs.length - 1]?.innerText || 'No response';

// ✅ CORRECT - Traditional check
if (msgs.length > 0) {
  return msgs[msgs.length - 1].innerText;
}
return 'No response';

✅ DO: Use Function Wrappers

// ❌ WRONG - Direct code
fn: `{ const paras = document.querySelectorAll('p'); ... }`

// ✅ CORRECT - Function wrapper
fn: `(function() { 
  const paras = document.querySelectorAll('p'); 
  return ...; 
})()`

4. Debugging & Testing

✅ DO: Add Debug Logging

const debugInfo = await browser({
  action: "act",
  kind: "evaluate",
  profile: "openclaw",
  targetId: tabId,
  fn: `(function() {
    const paragraphs = document.querySelectorAll('p');
    console.log('Found', paragraphs.length, 'paragraphs');
    
    // Log first few paragraphs for debugging
    for (let i = 0; i < Math.min(paragraphs.length, 5); i++) {
      console.log('Paragraph', i, ':', paragraphs[i].innerText.substring(0, 100));
    }
    
    return JSON.stringify({
      paragraphCount: paragraphs.length,
      sampleTexts: Array.from(paragraphs).slice(0, 3).map(p => p.innerText.substring(0, 50))
    });
  })()`,
  returnByValue: true
});

console.log("Debug info:", debugInfo);

✅ DO: Test Extraction Before Reliance

// Test the extraction function with a simple question first
const testQuestion = "What is 2+2?";
await askQuestion(tabId, testQuestion);
const testResponse = await extractDeepSeekResponse(tabId);
console.log("Test response:", testResponse);

// If test works, proceed with actual question
if (testResponse && testResponse.includes('4')) {
  console.log("✅ Extraction test passed");
  // Proceed with actual question
}

5. Common Failure Patterns to Avoid

Failure PatternSolution
"No response found"Increase wait time, use robust extraction, check page structure
JavaScript syntax errorsFix regex patterns, avoid optional chaining, use function wrappers
Element not foundUse semantic selectors, take fresh snapshot, add fallbacks
Login timeoutIncrease timeout, implement QR refresh, better error messaging
Event validation failsUse kind: "press" not dispatchEvent()
<tool_call>DO NOT send raw html tags content to user session. Just retry to extract or tell user to go on asking.

6. Quick Reference: Working Implementation

// Most reliable implementation pattern
async function askDeepSeekReliably(tabId, question) {
  try {
    // 1. Ensure fresh chat session
    await startFreshChat(tabId);
    
    // 2. Type question with proper event handling
    await browser({
      action: "act",
      kind: "type",
      profile: "openclaw",
      targetId: tabId,
      text: question
    });
    
    // 3. Submit with press action (not dispatchEvent)
    await browser({
      action: "act",
      kind: "press",
      profile: "openclaw",
      targetId: tabId,
      key: "Enter"
    });
    
    // 4. Wait appropriately
    await new Promise(r => setTimeout(r, 15000));
    
    // 5. Extract with robust function
    const response = await extractDeepSeekResponse(tabId);
    
    // 6. Handle potential failures
    if (response.includes('No response found') || response.length < 10) {
      // Try fallback extraction
      return await fallbackExtraction(tabId);
    }
    
    return response;
  } catch (error) {
    console.error("DeepSeek query failed:", error);
    return `Error: ${error.message}`;
  }
}

7. When to Use Which Approach

Use CaseRecommended FunctionWait TimeNotes
Simple factual questionsextractDeepSeekResponse10sFast, reliable for most cases
Complex reasoning questionsultraRobustExtractDeepSeekResponse15-20sHandles complex page structures
DeepThink mode responsesextractDeepSeekResponse with DeepThink enabled20sLonger thinking time needed
Critical queriesTry multiple extraction methods20s+Combine results for reliability

See Also

  • imsg skill - Send results to iMessage
  • openclaw channels status skill - Get enabled channels
  • openclaw browser status skill - Get browser status
  • browser tool - OpenClaw browser control

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Zip

Zip - command-line tool for everyday use

Registry SourceRecently Updated
General

Youtube Script

YouTube视频脚本、标题A/B测试、缩略图文案、SEO优化、开头Hook、章节标记。YouTube script writer with title testing, thumbnail copy, SEO optimization, hooks, chapter markers. Use when you...

Registry SourceRecently Updated
1760ckchzh
General

Topmediai AI Music Generator

Generate AI music, BGM, or lyrics via TopMediai API. Supports auto polling and two-stage output (preview first, then final full audio) for generation tasks.

Registry SourceRecently Updated
General

Yamlcheck

YAML validator and formatter. Validate YAML syntax, pretty-print with proper indentation, convert between YAML and JSON, and lint YAML files for common issues.

Registry SourceRecently Updated