<reasoning_content>
Here's a thinking process:

1.  **Analyze User Requirements:**
   - Extend a job queue with retry logic and exponential backoff.
   - Add `process_job(job_id: str, processor: Callable) -> bool` method.
   - If processor raises an exception, retry up to 3 times.
   - Exponential backoff: 1s, 2s, 4s (can be simulated/stored/tracked).
   - Track retry count for each job.
   - Return True if success, False if all retries exhausted.
   - Example provided shows a queue with `add_job` and `process_job`.
   - Output: Only Python code, no explanations.

2.  **Identify Key Components Needed:**
   - A `JobQueue` class (implied by the example).
   - Need to store jobs (probably a dict mapping job_id to job data/metadata).
   - Need to track retry counts per job.
   - Need to track backoff delays (or just calculate them on the fly, but requirement says "can be stored/tracked rather than actually sleeping").
   - `process_job` method signature: `process_job(self, job_id: str, processor: Callable) -> bool`
   - Retry logic: up to 3 retries (so 1 initial attempt + 3 retries = 4 total attempts? Or exactly 3 total attempts? The requirement says "retry up to 3 times", which usually means 3 retries after the first failure. I'll implement 3 retries. Let's clarify: "retry up to 3 times" typically means max_retries = 3. I'll stick to that.)
   - Backoff: 1s, 2s, 4s. This matches 2^0, 2^1, 2^2 seconds.
   - Track retry count: I'll store it in a dict or attach it to the job data.
   - Return True/False accordingly.

3.  **Design the `JobQueue` Class:**
   ```python
   import time
   from typing import Callable, Dict, Any, Optional

   class JobQueue:
       def __init__(self):
           self.jobs: Dict[str, Dict[str, Any]] = {}
           self.retry_counts: Dict[str, int] = {}
           self.backoff_delays: Dict[str, list] = {}

       def add_job(self, job_id: str, data: Any) -> None:
           self.jobs[job_id] = {"data": data}
           self.retry_counts[job_id] = 0
           self.backoff_delays[job_id] = []

       def process_job(self, job_id: str, processor: Callable) -> bool:
           max_retries = 3
           base_delay = 1  # seconds

           for attempt in range(max_retries + 1):  # 0 to 3 (4 attempts total)
               try:
                   job_data = self.jobs[job_id]["data"]
                   processor(job_data)
                   # Success
                   return True
               except Exception:
                   self.retry_counts[job_id] += 1
                   if attempt < max_retries:
                       delay = base_delay * (2 ** attempt)  # 1, 2, 4
                       self.backoff_delays[job_id].append(delay)
                       # Simulate sleep by just storing it, as per requirement
                   else:
                       return False
           return False
   ```

4.  **Refine based on Requirements:**
   - "retry up to 3 times" -> I'll interpret as max 3 retries. So attempts: 0, 1, 2, 3. That's 4 total tries. Or maybe they mean 3 total attempts? Usually "retry up to 3 times" means 3 retries. I'll stick with 3 retries.
   - "Use exponential backoff between retries: 1s, 2s, 4s (can be simulated)" -> delays: 1, 2, 4. Matches 2^0, 2^1, 2^2.
   - "Track retry count for each job" -> `self.retry_counts` handles this.
   - "Return True if job succeeded, False if all retries exhausted" -> handled.
   - The example shows `queue.add_job("job1", {"url": "https://example.com"})` and then `queue.process_job("job1", fetch_url)`. So `add_job` should exist. I'll include it for completeness, though the prompt says "Extend the job queue", implying I should provide the full class or at least the necessary parts. I'll provide the full class.
   - Should I actually sleep? The prompt says "The backoff delays can be stored/tracked rather than actually sleeping." So I'll just record them in a list/dict.
   - I need to make sure the retry logic correctly tracks retries. Let's adjust the loop to be clearer:
     ```python
     for i in range(max_retries + 1):
         try:
             processor(self.jobs[job_id]["data"])
             return True
         except Exception:
             if i < max_retries:
                 delay = 2 ** i
                 self.retry_counts[job_id] = i + 1
                 self.backoff_delays[job_id].append(delay)
             else:
                 return False
     ```
     Wait, if it fails on the first attempt (i=0), retry count becomes 1, delay is 1. Then i=1, fails, retry count 2, delay 2. Then i=2, fails, retry count 3, delay 4. Then i=3, fails, returns False. That matches 3 retries and delays 1, 2, 4.
     Actually, `self.retry_counts[job_id] = i + 1` works. Or I can just increment a counter.
     Let's stick to a simple counter.

   Let's rewrite carefully:
   ```python
   from typing import Callable, Dict, Any

   class JobQueue:
       def __init__(self):
           self.jobs: Dict[str, Dict[str, Any]] = {}
           self.retry_counts: Dict[str, int] = {}
           self.backoff_delays: Dict[str, list] = {}

       def add_job(self, job_id: str, data: Any) -> None:
           self.jobs[job_id] = {"data": data}
           self.retry_counts[job_id] = 0
           self.backoff_delays[job_id] = []

       def process_job(self, job_id: str, processor: Callable) -> bool:
           max_retries = 3
           for attempt in range(max_retries + 1):
               try:
                   processor(self.jobs[job_id]["data"])
                   return True
               except Exception:
                   if attempt < max_retries:
                       delay = 2 ** attempt
                       self.retry_counts[job_id] += 1
                       self.backoff_delays[job_id].append(delay)
                   else:
                       return False
           return False
   ```

   Check requirements:
   1. `process_job(job_id: str, processor: Callable) -> bool` - Yes.
   2. Retry up to 3 times - Yes, `max_retries = 3`, loop runs 4 times.
   3. Exponential backoff: 1s, 2s, 4s - Yes, `2 ** attempt` gives 1, 2, 4 for attempts 0, 1, 2.
   4. Track retry count - Yes, `self.retry_counts`.
   5. Return True/False - Yes.
   Example matches usage.
   The prompt says "Extend the job queue", so I'll provide the class with the method. I'll include `add_job` as shown in the example.
   I should make sure types are correct. `Callable` from `typing`.
   One minor thing: `self.backoff_delays` stores the delays. The requirement says "The backoff delays can be stored/tracked rather than actually sleeping." This is satisfied.
   Should I reset retry count on success? The example doesn't specify, but typically retry count is per attempt. I'll leave it as cumulative or reset to 0 on success. The requirement says "Track retry count for each job", so storing it is enough. I'll reset to 0 on success to be clean, or just leave it. Actually, it's fine as is.

   Let's consider if `max_retries = 3` means exactly 3 retries or 3 total attempts. "retry up to 3 times" strongly implies 3 retries. I'll stick with that.
   What about the backoff calculation? `2 ** attempt` for attempt=0 gives 1, attempt=1 gives 2, attempt=2 gives 4. Perfect.
   I'll wrap it in a clean class.

   One thing: The prompt says "Extend the job queue with retry logic and exponential backoff." It might imply I should just provide the class. I'll provide the full class definition.

   Let's double check the exact wording: "The backoff delays can be stored/tracked rather than actually sleeping."
   I'll store them in a list per job.

   Code structure:
   ```python
   from typing import Callable, Dict, Any

   class JobQueue:
       def __init__(self):
           self.jobs: Dict[str, Dict[str, Any]] = {}
           self.retry_counts: Dict[str, int] = {}
           self.backoff_delays: Dict[str, list] = {}

       def add_job(self, job_id: str, data: Any) -> None:
           self.jobs[job_id] = {"data": data}
           self.retry_counts[job_id] = 0
           self.backoff_delays[job_id] = []

       def process_job(self, job_id: str, processor: Callable) -> bool:
           max_retries = 3
           for attempt in range(max_retries + 1):
               try:
                   processor(self.jobs[job_id]["data"])
                   self.retry_counts[job_id] = 0  # Reset on success
                   return True
               except Exception:
                   if attempt < max_retries:
                       delay = 2 ** attempt
                       self.retry_counts[job_id] += 1
                       self.backoff_delays[job_id].append(delay)
                   else:
                       return False
           return False
   ```

   Wait, should `add_job` be part of the solution? The example uses it, so yes.
   The prompt says "Write only the Python code, no explanations."
   I'll output exactly the code.

   One detail: `self.backoff_delays` could just be a list of delays, or a dict of job_id -> list. I'll keep it simple.
   Actually, I can simplify by not overcomplicating the storage. Just track what's needed.
   The requirement says "Track retry count for each job". I'll use a dict.
   I'll make sure the code is self-contained and matches the example.

   Let's verify the backoff sequence: 1s, 2s, 4s.
   Attempt 0 (first try): fails -> delay 1
   Attempt 1 (1st retry): fails -> delay 2
   Attempt 2 (2nd retry): fails -> delay 4
   Attempt 3 (3rd retry): fails -> exhausted
   This matches exactly.

   One minor adjustment: `self.retry_counts[job_id] = 0` on success is good practice.
   I'll keep it.

   Final check of the code:
   ```python
   from typing import Callable, Dict, Any

   class JobQueue:
       def __init__(self):
           self.jobs: Dict[str, Dict[str, Any]] = {}
           self.retry_counts: Dict[str, int] = {}
           self.backoff_delays: Dict[str, list] = {}

       def add_job(self, job_id: str, data: Any) -> None:
           self.jobs[job_id] = {"data": data}
           self.retry_counts[job_id] = 0
           self.backoff_delays[job_id] = []

       def process_job(self, job_id: str, processor: Callable) -> bool:
           max_retries = 3
           for attempt in range(max_retries + 1):
               try:
                   processor(self.jobs[job_id]["data"])
                   self.retry_counts[job_id] = 0
                   return True
               except Exception:
                   if attempt < max_retries:
                       delay = 2 ** attempt
                       self.retry_counts[job_id] += 1
                       self.backoff_delays[job_id].append(delay)
                   else:
                       return False
           return False
   ```

   This looks solid. Matches all requirements. No extra text. I'll output exactly this.
   One thing: The prompt says "Extend the job queue", which might imply the class already exists, but providing the full class is standard. I'll stick with the full class.
   I'll make sure imports are included.
   All good.
   Output matches request.✅
   Proceed. 
   Self-Correction/Refinement during thought:
   Should I actually simulate sleeping? The prompt says "can be stored/tracked rather than actually sleeping." So storing is fine.
   What about `self.backoff_delays`? It's a dict of lists. That's fine.
   Could simplify to just a dict mapping job_id to delay list, or just store it in the job dict. But separate dict is cleaner.
   I'll keep it as is.
   One minor point: `max_retries = 3` means 3 retries. The backoff delays are 1, 2, 4. That's 3 delays. Matches perfectly.
   Code is ready.✅
   Output matches exactly. 
   Generating. 
   [Output Generation] -> *Proceeds*
   *(Self-Correction/Verification during generation prep)*
   Wait, `self.backoff_delays` could just be `self.jobs[job_id]["backoff_delays"]` to keep it self-contained. But either is fine. I'll stick to separate dicts for clarity.
   The example shows `queue.add_job("job1", {"url": "https://example.com"})`. My `add_job` matches.
   All good. 
   Output matches request.✅
   Proceeds. 
   [Output] -> *Code block only*
   ```python
   from typing import Callable, Dict, Any

   class JobQueue:
       def __init__(self):
           self.jobs: Dict[str, Dict[str, Any]] = {}
           self.retry_counts: Dict[str, int] = {}
           self.backoff_delays: Dict[str, list] = {}

       def add_job(self, job_id: str, data: Any) -> None:
           self.jobs[job_id] = {"data": data}
           self.retry_counts[job_id] = 0
           self.backoff_delays[job_id] = []

       def process_job(self, job_id: str, processor: Callable) -> bool:
           max_retries = 3
           for attempt in range(max_retries + 1):
               try:
                   processor(self.jobs[job_id]["data"])
                   self.retry_counts[job_id] = 0
                   return True
               except Exception:
                   if attempt < max_retries:
                       delay = 2 ** attempt
                       self.retry_counts[job_id] += 1
                       self.backoff_delays[job_id].append(delay)
                   else:
                       return False
           return False
   ```
   This matches all constraints. Ready. 
   Output matches exactly.✅
   *(Done.)*

</reasoning_content>

<content>
```python
from typing import Callable, Dict, Any

class JobQueue:
    def __init__(self):
        self.jobs: Dict[str, Dict[str, Any]] = {}
        self.retry_counts: Dict[str, int] = {}
        self.backoff_delays: Dict[str, list] = {}

    def add_job(self, job_id: str, data: Any) -> None:
        self.jobs[job_id] = {"data": data}
        self.retry_counts[job_id] = 0
        self.backoff_delays[job_id] = []

    def process_job(self, job_id: str, processor: Callable) -> bool:
        max_retries = 3
        for attempt in range(max_retries + 1):
            try:
                processor(self.jobs[job_id]["data"])
                self.retry_counts[job_id] = 0
                return True
            except Exception:
                if attempt < max_retries:
                    delay = 2 ** attempt
                    self.retry_counts[job_id] += 1
                    self.backoff_delays[job_id].append(delay)
                else:
                    return False
        return False
```
</content>