File size: 4,860 Bytes
5d61448
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""
TD Lang Errors — Clear, helpful error messages.

Milan is 11 — errors should say what went wrong and where,
not dump cryptic stack traces.
"""


class TDLangError(Exception):
    """Base error for all td_lang errors."""

    def __init__(self, message: str, line: int | None = None, hint: str | None = None):
        self.line = line
        self.hint = hint
        if line is not None:
            full = f"Line {line}: {message}"
        else:
            full = message
        if hint:
            full += f"\n  Hint: {hint}"
        super().__init__(full)


class TDSyntaxError(TDLangError):
    """Bad .td syntax — couldn't understand the file."""
    pass


class TDCompileError(TDLangError):
    """Valid syntax but impossible plan — e.g., merging into a model that doesn't exist."""
    pass


class TDGateError(TDLangError):
    """Gates failed during execution."""

    def __init__(self, failed_gates: list[str], message: str = ""):
        self.failed_gates = failed_gates
        msg = message or f"Gates failed: {', '.join(failed_gates)}"
        super().__init__(msg, hint="Check eval results — the model may have regressed.")


class TDBudgetError(TDLangError):
    """Budget would be exceeded — compiler refuses to run."""

    def __init__(self, field: str, limit: float, requested: float):
        self.field = field
        self.limit = limit
        self.requested = requested
        super().__init__(
            f"Budget exceeded: {field} limit is {limit}, but plan needs ~{requested}",
            hint="Reduce steps, use fewer merges, or increase the budget.",
        )


class TDContractError(TDLangError):
    """Data or reward contract violation — training data doesn't match spec."""

    def __init__(self, contract_type: str, violations: list[str]):
        self.contract_type = contract_type
        self.violations = violations
        msg = f"{contract_type} contract failed with {len(violations)} violation(s)"
        if violations:
            msg += f": {violations[0]}"
            if len(violations) > 1:
                msg += f" (and {len(violations)-1} more)"
        super().__init__(
            msg,
            hint="Check your training data matches the contract spec.",
        )


# ============================================================================
# COMMON MISTAKE SUGGESTIONS (Phase 5)
# ============================================================================

COMMON_FIXES = {
    "load": 'Did you forget quotes? Correct: load "model/path" as name',
    "merge": 'Format: merge "source" into target using method [strength 0.5]',
    "edit": "Format: edit target layers 16-28 using lora [lr 1e-4]",
    "prune": "Format: prune target using wanda [aggressiveness 0.2]",
    "fork": "Format: fork source as new_name",
    "reset": 'Format: reset target to "checkpoint_path"',
    "train": 'Format: train target on "dataset" using grpo [steps 64]',
    "synth": "Format: synth target from source [filter cherry_llm]",
    "snapshot": "Format: snapshot target [-> output_dir]",
    "report": "Format: report [-> economics.json]",
    "fuse": 'Format: fuse ["model1", "model2"] into target [strategy equal]',
    "absorb": 'Format: absorb "model" into target [strength 0.5]',
    "schedule": 'Format: schedule "every 6h" { commands... } or schedule "at 02:00" { ... }',
    "download": 'Format: download "dataset_name" as alias [split train]',
    "log": 'Format: log "output.txt" (place before commands to capture output)',
    "compare": 'Format: compare target vs "source_model" [questions 50] [-> output.json]',
    "verify": 'Format: verify target on "dataset" [questions 100] [-> output.json]',
    "vote": 'Format: vote target "question" [samples 5] [-> output.json]',
    "prompt": 'Format: prompt target "Think step by step before answering."',
    "distill": 'Format: distill target into "small_model" [steps 200] [-> output_dir]',
    "rollback": "Format: rollback target (reverts to most recent snapshot)",
    "curriculum": 'Format: curriculum target on "dataset" using grpo [levels 3] [steps 64]',
    "star": 'Format: star target on "dataset" [rounds 3] [samples 8]',
    "best_of": 'Format: best_of target on "dataset" [n 8] [steps 32]',
    "exploit": 'Format: exploit target on "dataset" [samples 16] [steps 32] [-> output.jsonl]',
    "arena": 'Format: arena target on "dataset" [rounds 5] [episodes 50] [steps 64] [curiosity 0.3] [-> log.json]',
    "research_arena": 'Format: research_arena target topic "subject" [sources "pubmed"|"web"|"arxiv"] [rounds 5] [episodes 30] [-> log.json]',
}


def suggest_fix(token: str) -> str | None:
    """Given a failed token, suggest the correct syntax."""
    token_lower = token.lower().strip()
    for keyword, fix in COMMON_FIXES.items():
        if keyword in token_lower:
            return fix
    return None