@@ -426,6 +426,14 @@ class ResponseRepairer: |
| 426 | 426 | project_root=self.context.project_root, |
| 427 | 427 | todo_label=next_pending or "", |
| 428 | 428 | ) |
| 429 | + urgent_retry_message = self._urgent_empty_write_retry_message( |
| 430 | + concrete_target, |
| 431 | + outline_label=outline_label, |
| 432 | + retry_number=retry_number, |
| 433 | + max_empty_retries=max_empty_retries, |
| 434 | + ) |
| 435 | + if urgent_retry_message is not None: |
| 436 | + return urgent_retry_message |
| 429 | 437 | if ( |
| 430 | 438 | next_pending |
| 431 | 439 | and _todo_is_mutation_step(next_pending) |
@@ -1608,23 +1616,64 @@ class ResponseRepairer: |
| 1608 | 1616 | if outline_label and outline_label.strip() |
| 1609 | 1617 | else self._fallback_html_label(target) |
| 1610 | 1618 | ) |
| 1619 | + return ( |
| 1620 | + "If blanking continues, use this minimal starter payload shape inside the `write` call now: " |
| 1621 | + f"`{self._minimal_html_payload(target, label)}` and refine it later." |
| 1622 | + ) |
| 1623 | + |
| 1624 | + def _urgent_empty_write_retry_message( |
| 1625 | + self, |
| 1626 | + target: Path, |
| 1627 | + *, |
| 1628 | + outline_label: str | None, |
| 1629 | + retry_number: int, |
| 1630 | + max_empty_retries: int, |
| 1631 | + ) -> str | None: |
| 1632 | + if retry_number < max_empty_retries: |
| 1633 | + return None |
| 1634 | + if target.suffix.lower() not in {".html", ".htm"}: |
| 1635 | + return None |
| 1636 | + label = ( |
| 1637 | + outline_label.strip() |
| 1638 | + if outline_label and outline_label.strip() |
| 1639 | + else self._fallback_html_label(target) |
| 1640 | + ) |
| 1641 | + payload = self._minimal_html_payload(target, label) |
| 1642 | + return "\n".join( |
| 1643 | + [ |
| 1644 | + "[EMPTY ASSISTANT RESPONSE]", |
| 1645 | + ( |
| 1646 | + "Your last response was empty " |
| 1647 | + f"(retry {retry_number}/{max_empty_retries}). Emit one tool call only:" |
| 1648 | + ), |
| 1649 | + ( |
| 1650 | + "write(file_path=" |
| 1651 | + f"{json.dumps(display_runtime_path(target))}, " |
| 1652 | + f"content={json.dumps(payload)})" |
| 1653 | + ), |
| 1654 | + "No prose, no TodoWrite, no reads.", |
| 1655 | + ] |
| 1656 | + ) |
| 1657 | + |
| 1658 | + def _minimal_html_payload(self, target: Path, label: str) -> str: |
| 1611 | 1659 | if self._is_index_html_target(target): |
| 1612 | 1660 | return ( |
| 1613 | | - "If blanking continues, use this minimal starter payload shape inside the `write` call now: " |
| 1614 | | - f"`<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" " |
| 1615 | | - f"content=\"width=device-width, initial-scale=1.0\"><title>{label}</title></head><body>" |
| 1616 | | - f"<div class=\"container\"><h1>{label}</h1><p>...</p><nav><ul>" |
| 1617 | | - "<li><a href=\"chapters/01-...html\">Chapter 1: ...</a></li>" |
| 1618 | | - "<li><a href=\"chapters/02-...html\">Chapter 2: ...</a></li>" |
| 1619 | | - "</ul></nav></div></body></html>` and refine it later." |
| 1661 | + '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">' |
| 1662 | + '<meta name="viewport" content="width=device-width, initial-scale=1.0">' |
| 1663 | + f"<title>{label}</title></head><body><div class=\"container\"><h1>{label}</h1>" |
| 1664 | + "<p>Starter overview for this guide.</p><nav><ul>" |
| 1665 | + '<li><a href="chapters/01-introduction.html">Chapter 1: Introduction</a></li>' |
| 1666 | + '<li><a href="chapters/02-installation.html">Chapter 2: Installation</a></li>' |
| 1667 | + "</ul></nav></div></body></html>" |
| 1620 | 1668 | ) |
| 1621 | 1669 | return ( |
| 1622 | | - "If blanking continues, use this minimal starter payload shape inside the `write` call now: " |
| 1623 | | - f"`<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" " |
| 1624 | | - f"content=\"width=device-width, initial-scale=1.0\"><title>{label}</title></head><body>" |
| 1625 | | - f"<div class=\"container\"><h1>{label}</h1><p>...</p><h2>Overview</h2><p>...</p>" |
| 1626 | | - f"<h2>Key Steps</h2><p>...</p><p><a href=\"../index.html\">← Back to Main Guide Index</a></p>" |
| 1627 | | - "</div></body></html>` and refine it later." |
| 1670 | + '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8">' |
| 1671 | + '<meta name="viewport" content="width=device-width, initial-scale=1.0">' |
| 1672 | + f"<title>{label}</title></head><body><div class=\"container\"><h1>{label}</h1>" |
| 1673 | + "<p>Starter content for this chapter.</p><h2>Overview</h2><p>Key concepts go here.</p>" |
| 1674 | + "<h2>Key Steps</h2><p>Practical steps go here.</p>" |
| 1675 | + '<p><a href="../index.html">Back to Main Guide Index</a></p>' |
| 1676 | + "</div></body></html>" |
| 1628 | 1677 | ) |
| 1629 | 1678 | |
| 1630 | 1679 | @staticmethod |