# 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.

- Skill: `dvcrn/freechat-deepseek-2` (Agent Skill)
- Install (CLI): `npx skillmds@latest add dvcrn/freechat-deepseek-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dvcrn/freechat-deepseek-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: dvcrn (https://skillmd.com/u/dvcrn)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/dvcrn/freechat-deepseek-2

---


> Generated note: shared plugin assets for this package live at the plugin root. Common local references were rewritten when they appeared in backticks or markdown links.

# 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.

```javascript
// 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

```javascript
// 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?)

```javascript
// 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

|       Status         |               Check              |          Action Required     |
|----------------------|----------------------------------|------------------------------|
| ✅ Already Logged In | Chat input visible + user avatar | Proceed to Step 5            |
| ❌ Need Login        | QR Code or login form visible    | Proceed to Step 3            |

---

## Step 3: Send QR Code to Enabled Channels

```javascript
// 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)

```javascript
// 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

| Attempt | Time    | Action                          |
|---------|---------|---------------------------------|
| 1-12    | 0-60s   | Poll every 5s, wait for scan    |
| 12      | 60s     | Refresh page, re-send QR code   |
| 13-24   | 65-120s | Continue polling                |
| 24      | 120s    | Fail with timeout error         |

---

## Step 5: Input Question and Press Enter

```javascript
// 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.

```javascript
// 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

|      Element |     Strategy    |
|--------------|-----------------|
| Container    | `document.body` |
| Message type | `<p>` tags      |
| Filter out   | AI-generated, Upload docs, Help text, Keyboard shortcuts |
| Get          | Last matching `<p>` from body |

---

## Complete Example: Full Workflow

```javascript
// ============ 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

|      Element       |        Selector       |
|--------------------|-----------------------|
| Chat input         | `textarea[placeholder*="Message DeepSeek"]` |
| Send (Enter)       | Press Enter key       |
| QR Code            | `img[src*="wechat"], iframe[src*="wechat"]` |
| User avatar        | `[class*="avatar"], [class*="user"]` |
| Response content   | Last `<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
   ```bash
   export DEEPSEEK_PHONE="+1234567890000"
   ```

2. **USER.md**: Add phone number to USER.md file
   ```markdown
   # USER.md
   Phone: +1234567890000
   ```

3. **Configuration File**: Add to OpenClaw configuration
   ```javascript
   // 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:
```javascript
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

| Issue                  | Solution |
|------------------------|----------|
| Input not found        | Refresh page, take new snapshot |
| Enter not working      | Use browser act kind="press" with key="Enter" |
| ❌ Enter via JS dispatchEvent doesn't work | DeepSeek uses React/event validation - must use `kind: "press"` with `key: "Enter"` instead |
| Response not found     | Wait longer, check page rendering |
| QR Code timeout        | Automatically refreshes and re-sends |
| Login with phone       | DO NOT ask and input phone number |
| All channels fail      | Ask 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)

```javascript
// 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)

```javascript
// 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:

```javascript
// 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:

```javascript
// 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

```javascript
// 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:

```javascript
// 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:

| Scenario | Recommended Approach | Why |
|----------|---------------------|-----|
| Previous response was "Sorry, that's beyond my current scope" | **Start Fresh Chat** | DeepSeek might be in a restricted mode; fresh chat resets context |
| Want to ask unrelated follow-up | **Start Fresh Chat** | Avoids confusing the AI with previous context |
| Continuing same topic with refined question | **Continue in Current Chat** | Maintains context for better responses |
| Previous response was good but need clarification | **Continue in Current Chat** | AI 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

```javascript
// 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

…(truncated)
