@@ -418,7 +418,7 @@ class ResponseRepairer: |
| 418 | 418 | ) |
| 419 | 419 | else: |
| 420 | 420 | first_line = f"Create `{concrete_target.name}` now." |
| 421 | | - compact_retry = retry_number >= 4 |
| 421 | + compact_retry = True |
| 422 | 422 | |
| 423 | 423 | lines = [ |
| 424 | 424 | first_line, |
@@ -434,19 +434,6 @@ class ResponseRepairer: |
| 434 | 434 | ) |
| 435 | 435 | if html_scaffold_line: |
| 436 | 436 | lines.append(html_scaffold_line) |
| 437 | | - reference_line = self._known_reference_structure_line( |
| 438 | | - concrete_target, |
| 439 | | - require_first_substantive_output=True, |
| 440 | | - ) |
| 441 | | - if reference_line and not compact_retry: |
| 442 | | - lines.append(reference_line) |
| 443 | | - reference_cues_line = self._known_reference_cues_line( |
| 444 | | - concrete_target, |
| 445 | | - require_first_substantive_output=True, |
| 446 | | - retry_number=retry_number, |
| 447 | | - ) |
| 448 | | - if reference_cues_line and not compact_retry: |
| 449 | | - lines.append(reference_cues_line) |
| 450 | 437 | html_starter_line = self._known_html_starter_shape_line( |
| 451 | 438 | concrete_target, |
| 452 | 439 | require_first_substantive_output=True, |
@@ -455,14 +442,6 @@ class ResponseRepairer: |
| 455 | 442 | ) |
| 456 | 443 | if html_starter_line: |
| 457 | 444 | lines.append(html_starter_line) |
| 458 | | - html_template_line = self._known_html_starter_template_line( |
| 459 | | - concrete_target, |
| 460 | | - require_first_substantive_output=True, |
| 461 | | - retry_number=retry_number, |
| 462 | | - outline_label=outline_label, |
| 463 | | - ) |
| 464 | | - if html_template_line: |
| 465 | | - lines.append(html_template_line) |
| 466 | 445 | if ( |
| 467 | 446 | not compact_retry |
| 468 | 447 | and _should_encourage_initial_version( |
@@ -929,25 +908,6 @@ class ResponseRepairer: |
| 929 | 908 | lines.append( |
| 930 | 909 | f"Use the existing outline label `{outline_label}` for that file so it matches the current guide structure." |
| 931 | 910 | ) |
| 932 | | - reference_line = self._known_reference_structure_line( |
| 933 | | - concrete_target, |
| 934 | | - require_first_substantive_output=( |
| 935 | | - has_confirmed_output_file_progress |
| 936 | | - and not has_confirmed_substantive_output_file_progress |
| 937 | | - ), |
| 938 | | - ) |
| 939 | | - if reference_line: |
| 940 | | - lines.append(reference_line) |
| 941 | | - reference_cues_line = self._known_reference_cues_line( |
| 942 | | - concrete_target, |
| 943 | | - require_first_substantive_output=( |
| 944 | | - has_confirmed_output_file_progress |
| 945 | | - and not has_confirmed_substantive_output_file_progress |
| 946 | | - ), |
| 947 | | - retry_number=retry_number, |
| 948 | | - ) |
| 949 | | - if reference_cues_line: |
| 950 | | - lines.append(reference_cues_line) |
| 951 | 911 | html_scaffold_line = self._known_existing_html_scaffold_line( |
| 952 | 912 | concrete_target, |
| 953 | 913 | require_first_substantive_output=( |
@@ -1257,19 +1217,6 @@ class ResponseRepairer: |
| 1257 | 1217 | has_confirmed_output_file_progress |
| 1258 | 1218 | and not has_confirmed_substantive_output_file_progress |
| 1259 | 1219 | ) |
| 1260 | | - reference_line = self._known_reference_structure_line( |
| 1261 | | - target, |
| 1262 | | - require_first_substantive_output=first_substantive_output, |
| 1263 | | - ) |
| 1264 | | - if reference_line: |
| 1265 | | - lines.append(reference_line) |
| 1266 | | - reference_cues_line = self._known_reference_cues_line( |
| 1267 | | - target, |
| 1268 | | - require_first_substantive_output=first_substantive_output, |
| 1269 | | - retry_number=retry_number, |
| 1270 | | - ) |
| 1271 | | - if reference_cues_line: |
| 1272 | | - lines.append(reference_cues_line) |
| 1273 | 1220 | html_scaffold_line = self._known_existing_html_scaffold_line( |
| 1274 | 1221 | target, |
| 1275 | 1222 | require_first_substantive_output=first_substantive_output, |
@@ -1485,40 +1432,6 @@ class ResponseRepairer: |
| 1485 | 1432 | return first_line or None |
| 1486 | 1433 | return None |
| 1487 | 1434 | |
| 1488 | | - def _known_reference_structure_line( |
| 1489 | | - self, |
| 1490 | | - target: Path, |
| 1491 | | - *, |
| 1492 | | - require_first_substantive_output: bool, |
| 1493 | | - ) -> str | None: |
| 1494 | | - if not require_first_substantive_output: |
| 1495 | | - return None |
| 1496 | | - reference = self._best_known_reference_path(target) |
| 1497 | | - if reference is None: |
| 1498 | | - return None |
| 1499 | | - return ( |
| 1500 | | - f"You already read `{display_runtime_path(reference)}`; reuse its overall " |
| 1501 | | - "structure as the starting pattern for this new file, then adapt the content " |
| 1502 | | - "to the current target." |
| 1503 | | - ) |
| 1504 | | - |
| 1505 | | - def _known_reference_cues_line( |
| 1506 | | - self, |
| 1507 | | - target: Path, |
| 1508 | | - *, |
| 1509 | | - require_first_substantive_output: bool, |
| 1510 | | - retry_number: int, |
| 1511 | | - ) -> str | None: |
| 1512 | | - if not require_first_substantive_output or retry_number < 2: |
| 1513 | | - return None |
| 1514 | | - reference = self._best_known_reference_path(target) |
| 1515 | | - if reference is None: |
| 1516 | | - return None |
| 1517 | | - cues = self._reference_content_cues(reference) |
| 1518 | | - if not cues: |
| 1519 | | - return None |
| 1520 | | - return f"Reference cues from `{display_runtime_path(reference)}`: {cues}" |
| 1521 | | - |
| 1522 | 1435 | def _known_existing_html_scaffold_line( |
| 1523 | 1436 | self, |
| 1524 | 1437 | target: Path, |
@@ -1578,31 +1491,6 @@ class ResponseRepairer: |
| 1578 | 1491 | "sections with short body text, and a back link to `../index.html`." |
| 1579 | 1492 | ) |
| 1580 | 1493 | |
| 1581 | | - def _known_html_starter_template_line( |
| 1582 | | - self, |
| 1583 | | - target: Path, |
| 1584 | | - *, |
| 1585 | | - require_first_substantive_output: bool, |
| 1586 | | - retry_number: int, |
| 1587 | | - outline_label: str | None, |
| 1588 | | - ) -> str | None: |
| 1589 | | - if not require_first_substantive_output or retry_number < 1: |
| 1590 | | - return None |
| 1591 | | - if target.suffix.lower() not in {".html", ".htm"}: |
| 1592 | | - return None |
| 1593 | | - label = outline_label.strip() if outline_label and outline_label.strip() else "this chapter" |
| 1594 | | - snippet = ( |
| 1595 | | - "<!DOCTYPE html> <html lang=\"en\"> <head> <meta charset=\"UTF-8\"> " |
| 1596 | | - f"<title>{label}</title> </head> <body> <div class=\"container\"> " |
| 1597 | | - f"<h1>{label}</h1> <p>...</p> <h2>Overview</h2> <p>...</p> " |
| 1598 | | - "<p><a href=\"../index.html\">← Back to Main Guide Index</a></p> " |
| 1599 | | - "</div> </body> </html>" |
| 1600 | | - ) |
| 1601 | | - return ( |
| 1602 | | - "If blanking continues, use this minimal HTML starter as the `content` value " |
| 1603 | | - f"and adapt it: `{snippet}`." |
| 1604 | | - ) |
| 1605 | | - |
| 1606 | 1494 | def _best_known_root_html_scaffold(self, target: Path) -> Path | None: |
| 1607 | 1495 | normalized_target = target.expanduser().resolve(strict=False) |
| 1608 | 1496 | if normalized_target.suffix.lower() not in {".html", ".htm"}: |
@@ -1638,87 +1526,6 @@ class ResponseRepairer: |
| 1638 | 1526 | ) |
| 1639 | 1527 | return siblings[0] |
| 1640 | 1528 | |
| 1641 | | - def _best_known_reference_path(self, target: Path) -> Path | None: |
| 1642 | | - normalized_target = target.expanduser().resolve(strict=False) |
| 1643 | | - target_tokens = { |
| 1644 | | - token |
| 1645 | | - for token in re.split(r"[^a-z0-9]+", normalized_target.stem.lower()) |
| 1646 | | - if token |
| 1647 | | - } |
| 1648 | | - target_number = _leading_numeric_prefix(normalized_target.stem) |
| 1649 | | - messages = list(getattr(self.context.session, "messages", []) or []) |
| 1650 | | - candidates: list[tuple[int, str, Path]] = [] |
| 1651 | | - |
| 1652 | | - for message in messages: |
| 1653 | | - for tool_call in getattr(message, "tool_calls", []) or []: |
| 1654 | | - if getattr(tool_call, "name", "") != "read": |
| 1655 | | - continue |
| 1656 | | - raw_path = str(tool_call.arguments.get("file_path") or "").strip() |
| 1657 | | - if not raw_path: |
| 1658 | | - continue |
| 1659 | | - candidate = Path(raw_path).expanduser().resolve(strict=False) |
| 1660 | | - if candidate == normalized_target or not candidate.suffix: |
| 1661 | | - continue |
| 1662 | | - if candidate.suffix.lower() != normalized_target.suffix.lower(): |
| 1663 | | - continue |
| 1664 | | - score = 0 |
| 1665 | | - if candidate.name.lower() == normalized_target.name.lower(): |
| 1666 | | - score += 8 |
| 1667 | | - if candidate.parent.name.lower() == normalized_target.parent.name.lower(): |
| 1668 | | - score += 2 |
| 1669 | | - if target_number and _leading_numeric_prefix(candidate.stem) == target_number: |
| 1670 | | - score += 3 |
| 1671 | | - candidate_tokens = { |
| 1672 | | - token |
| 1673 | | - for token in re.split(r"[^a-z0-9]+", candidate.stem.lower()) |
| 1674 | | - if token |
| 1675 | | - } |
| 1676 | | - score += min(3, len(target_tokens & candidate_tokens)) |
| 1677 | | - if score <= 0: |
| 1678 | | - continue |
| 1679 | | - candidates.append((score, str(candidate), candidate)) |
| 1680 | | - |
| 1681 | | - if not candidates: |
| 1682 | | - return None |
| 1683 | | - candidates.sort(key=lambda item: (item[0], item[1]), reverse=True) |
| 1684 | | - return candidates[0][2] |
| 1685 | | - |
| 1686 | | - def _reference_content_cues(self, reference: Path) -> str | None: |
| 1687 | | - try: |
| 1688 | | - content = reference.read_text() |
| 1689 | | - except OSError: |
| 1690 | | - return None |
| 1691 | | - |
| 1692 | | - suffix = reference.suffix.lower() |
| 1693 | | - cues: list[str] = [] |
| 1694 | | - if suffix in {".html", ".htm"}: |
| 1695 | | - for raw_line in content.splitlines(): |
| 1696 | | - stripped = " ".join(raw_line.strip().split()) |
| 1697 | | - if not stripped: |
| 1698 | | - continue |
| 1699 | | - lowered = stripped.lower() |
| 1700 | | - if not any( |
| 1701 | | - token in lowered |
| 1702 | | - for token in ("<title", "<h1", "<h2", "<p", "<li", "<a ") |
| 1703 | | - ): |
| 1704 | | - continue |
| 1705 | | - cues.append(_truncate_reference_cue(stripped)) |
| 1706 | | - if len(cues) >= 3: |
| 1707 | | - break |
| 1708 | | - if not cues: |
| 1709 | | - for raw_line in content.splitlines(): |
| 1710 | | - stripped = " ".join(raw_line.strip().split()) |
| 1711 | | - if not stripped: |
| 1712 | | - continue |
| 1713 | | - if sum(ch.isalpha() for ch in stripped) < 6: |
| 1714 | | - continue |
| 1715 | | - cues.append(_truncate_reference_cue(stripped)) |
| 1716 | | - if len(cues) >= 3: |
| 1717 | | - break |
| 1718 | | - if not cues: |
| 1719 | | - return None |
| 1720 | | - return " | ".join(cues) |
| 1721 | | - |
| 1722 | 1529 | @staticmethod |
| 1723 | 1530 | def _mutation_tool_scaffold(path: Path, *, tool_name: str) -> str: |
| 1724 | 1531 | normalized_path = json.dumps(display_runtime_path(path)) |
@@ -1759,19 +1566,4 @@ def _should_encourage_initial_version( |
| 1759 | 1566 | has_confirmed_output_file_progress: bool, |
| 1760 | 1567 | has_confirmed_substantive_output_file_progress: bool, |
| 1761 | 1568 | ) -> bool: |
| 1762 | | - if not has_confirmed_output_file_progress: |
| 1763 | | - return True |
| 1764 | | - if _is_summary_artifact_path(target): |
| 1765 | | - return False |
| 1766 | | - return not has_confirmed_substantive_output_file_progress |
| 1767 | | - |
| 1768 | | - |
| 1769 | | -def _leading_numeric_prefix(stem: str) -> str: |
| 1770 | | - match = re.match(r"^(\d+)", stem) |
| 1771 | | - return match.group(1) if match else "" |
| 1772 | | - |
| 1773 | | - |
| 1774 | | -def _truncate_reference_cue(value: str, *, max_chars: int = 96) -> str: |
| 1775 | | - if len(value) <= max_chars: |
| 1776 | | - return value |
| 1777 | | - return value[: max_chars - 3].rstrip() + "..." |
| 1569 | + return not has_confirmed_output_file_progress |