|
60 | 60 | } |
61 | 61 |
|
62 | 62 | # Model selection defaults |
63 | | -DEFAULT_PREFERRED_MODEL = "openai/gpt-5.4" |
64 | | -DEFAULT_FALLBACK_MODEL = "openai/gpt-4.1" |
| 63 | +DEFAULT_PREFERRED_MODEL = "anthropic/claude-sonnet-4.6" |
| 64 | +DEFAULT_FALLBACK_MODEL = "google/gemini-3-pro" |
65 | 65 | # Substrings in HTTP error bodies that indicate the model itself is unavailable (not a transient error) |
66 | 66 | _MODEL_UNAVAILABLE_SIGNALS = frozenset({ |
67 | 67 | "unknown_model", "model_not_found", "unsupported_model", "unsupported model", |
@@ -697,7 +697,7 @@ def build_analysis(root: pathlib.Path) -> Dict[str, Any]: |
697 | 697 | # ----------------------------- |
698 | 698 |
|
699 | 699 | def enrich_with_github_models(config: Config, analysis: Dict[str, Any]) -> Dict[str, Any]: |
700 | | - preferred = config.preferred_model or config.github_model |
| 700 | + preferred = config.github_model or config.preferred_model |
701 | 701 | fallback = config.fallback_model |
702 | 702 | meta: Dict[str, Any] = { |
703 | 703 | "enabled": False, |
@@ -975,7 +975,7 @@ def build_parse_errors_plan(config: Config, analysis: Dict[str, Any]) -> Optiona |
975 | 975 | errors = analysis.get("parse_error_files", []) |
976 | 976 | if not errors: |
977 | 977 | return None |
978 | | - preferred = config.preferred_model or config.github_model |
| 978 | + preferred = config.github_model or config.preferred_model |
979 | 979 | if not config.github_token or not preferred: |
980 | 980 | return None |
981 | 981 | fallback = config.fallback_model |
@@ -1042,7 +1042,7 @@ def build_import_cycles_plan(config: Config, analysis: Dict[str, Any]) -> Option |
1042 | 1042 | cycles = analysis.get("cycles", []) |
1043 | 1043 | if not cycles: |
1044 | 1044 | return None |
1045 | | - preferred = config.preferred_model or config.github_model |
| 1045 | + preferred = config.github_model or config.preferred_model |
1046 | 1046 | if not config.github_token or not preferred: |
1047 | 1047 | return None |
1048 | 1048 | fallback = config.fallback_model |
@@ -1128,7 +1128,7 @@ def build_entrypoint_consolidation_plan(config: Config, analysis: Dict[str, Any] |
1128 | 1128 | backend_eps = clusters.get("backend_servers", []) |
1129 | 1129 | if len(backend_eps) < _ENTRYPOINT_CONSOLIDATION_THRESHOLD: |
1130 | 1130 | return None |
1131 | | - preferred = config.preferred_model or config.github_model |
| 1131 | + preferred = config.github_model or config.preferred_model |
1132 | 1132 | if not config.github_token or not preferred: |
1133 | 1133 | return None |
1134 | 1134 | fallback = config.fallback_model |
@@ -1482,14 +1482,96 @@ def workflow_yaml(secret_env_names: Sequence[str], cron: str, github_model: Opti |
1482 | 1482 | run: | |
1483 | 1483 | mkdir -p .agent docs/repo_architect |
1484 | 1484 |
|
| 1485 | + - name: Resolve GitHub Models configuration |
| 1486 | + env: |
| 1487 | + GITHUB_TOKEN: ${{{{ github.token }}}} |
| 1488 | + run: | |
| 1489 | + python - <<'PY' |
| 1490 | + import json |
| 1491 | + import os |
| 1492 | + import urllib.request |
| 1493 | +
|
| 1494 | + order = [ |
| 1495 | + "anthropic/claude-sonnet-4.6", |
| 1496 | + "anthropic/claude-sonnet-4.5", |
| 1497 | + "openai/gpt-4.1", |
| 1498 | + ] |
| 1499 | + secondary = "google/gemini-3-pro" |
| 1500 | + available = set() |
| 1501 | + catalog_ok = False |
| 1502 | + try: |
| 1503 | + req = urllib.request.Request( |
| 1504 | + "https://models.github.ai/catalog/models", |
| 1505 | + headers={{ |
| 1506 | + "Authorization": f"Bearer {{os.environ['GITHUB_TOKEN']}}", |
| 1507 | + "Accept": "application/json", |
| 1508 | + "User-Agent": "repo-architect-workflow", |
| 1509 | + }}, |
| 1510 | + ) |
| 1511 | + with urllib.request.urlopen(req, timeout=30) as resp: |
| 1512 | + payload = json.loads(resp.read().decode("utf-8")) |
| 1513 | + models = payload.get("data", payload) if isinstance(payload, dict) else payload |
| 1514 | + if isinstance(models, list): |
| 1515 | + catalog_ok = True |
| 1516 | + for item in models: |
| 1517 | + if isinstance(item, dict): |
| 1518 | + model_id = item.get("id") or item.get("name") or item.get("model") |
| 1519 | + if isinstance(model_id, str) and model_id: |
| 1520 | + available.add(model_id) |
| 1521 | + except Exception as exc: |
| 1522 | + print(f"warning: GitHub Models catalog lookup failed; using defaults ({{exc}})") |
| 1523 | +
|
| 1524 | + def first_available(candidates): |
| 1525 | + for candidate in candidates: |
| 1526 | + if candidate in available: |
| 1527 | + return candidate |
| 1528 | + return None |
| 1529 | +
|
| 1530 | + def deterministic_available(exclude=None): |
| 1531 | + candidates = sorted(m for m in available if m != exclude) |
| 1532 | + return candidates[0] if candidates else None |
| 1533 | +
|
| 1534 | + if catalog_ok and available: |
| 1535 | + preferred = ( |
| 1536 | + first_available(order) |
| 1537 | + or (secondary if secondary in available else None) |
| 1538 | + or deterministic_available() |
| 1539 | + ) |
| 1540 | + else: |
| 1541 | + preferred = order[0] |
| 1542 | +
|
| 1543 | + if catalog_ok and available: |
| 1544 | + if secondary in available and secondary != preferred: |
| 1545 | + fallback = secondary |
| 1546 | + else: |
| 1547 | + fallback = ( |
| 1548 | + first_available([c for c in order if c != preferred]) |
| 1549 | + or deterministic_available(exclude=preferred) |
| 1550 | + or preferred |
| 1551 | + ) |
| 1552 | + else: |
| 1553 | + fallback = secondary |
| 1554 | +
|
| 1555 | + if not isinstance(preferred, str) or not preferred: |
| 1556 | + preferred = order[0] |
| 1557 | + if not isinstance(fallback, str) or not fallback: |
| 1558 | + fallback = secondary if secondary != preferred else order[-1] |
| 1559 | +
|
| 1560 | + env_file = os.environ.get("GITHUB_ENV") |
| 1561 | + if not env_file: |
| 1562 | + raise RuntimeError("GITHUB_ENV is not set; this internal workflow step must run inside GitHub Actions with environment-file support.") |
| 1563 | + with open(env_file, "a", encoding="utf-8") as fh: |
| 1564 | + fh.write(f"REPO_ARCHITECT_PREFERRED_MODEL={{preferred}}\\n") |
| 1565 | + fh.write(f"REPO_ARCHITECT_FALLBACK_MODEL={{fallback}}\\n") |
| 1566 | + print(f"selected preferred={{preferred}} fallback={{fallback}}") |
| 1567 | + PY |
| 1568 | +
|
1485 | 1569 | - name: Run repo architect |
1486 | 1570 | env: |
1487 | 1571 | GITHUB_TOKEN: ${{{{ github.token }}}} |
1488 | 1572 | GITHUB_REPO: ${{{{ github.repository }}}} |
1489 | 1573 | GITHUB_BASE_BRANCH: ${{{{ github.event.repository.default_branch }}}} |
1490 | 1574 | REPO_ARCHITECT_BRANCH_SUFFIX: ${{{{ github.run_id }}}}-${{{{ github.run_attempt }}}} |
1491 | | - REPO_ARCHITECT_PREFERRED_MODEL: openai/gpt-5.4 |
1492 | | - REPO_ARCHITECT_FALLBACK_MODEL: openai/gpt-4.1 |
1493 | 1575 | {extra_env} run: | |
1494 | 1576 | MODE="${{{{ github.event.inputs.mode }}}}" |
1495 | 1577 | MODEL="${{{{ github.event.inputs.github_model }}}}" |
|
0 commit comments