File size: 2,290 Bytes
6778532
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Exception hierarchy for the THOX mesh node agent.

Errors are split by *who can fix them*, because the agent reacts differently to
each class: configuration problems abort startup, transport problems are retried
with backoff, and contract rejections are surfaced verbatim so the operator can
see exactly which mesh rule was violated.
"""

from __future__ import annotations


class NodeError(Exception):
    """Base class for every error raised by the node agent."""


class ConfigError(NodeError):
    """Configuration is missing or self-contradictory. Not retryable."""


class BackendError(NodeError):
    """The local inference backend failed to start or produce a completion."""


class TunnelError(NodeError):
    """The public tunnel could not be established or its URL could not be read."""


class MeshTransportError(NodeError):
    """The mesh could not be reached (DNS, TLS, timeout, 5xx). Retryable."""


class MeshRejectedError(NodeError):
    """The mesh reached us and refused the request. Not retryable without a change.

    Carries the backend's own message rather than a paraphrase. The most common
    instance in this tier is the private-address rule in ``validateLocalBaseUrl``:
    ``meshstack-device-v2`` rejects any ``base_url`` whose host is not RFC1918,
    loopback, link-local, CGNAT or ``.local``. A Colab ``trycloudflare.com`` URL
    and an ``*.hf.space`` URL both fail that check, so the agent must be able to
    report the refusal precisely instead of retrying forever.
    """

    def __init__(self, message: str, *, status: int | None = None, action: str | None = None) -> None:
        super().__init__(message)
        self.status = status
        self.action = action

    def __str__(self) -> str:  # pragma: no cover - trivial formatting
        parts = [super().__str__()]
        if self.action:
            parts.append(f"action={self.action}")
        if self.status is not None:
            parts.append(f"status={self.status}")
        return " | ".join(parts)


class PublicUrlRejectedError(MeshRejectedError):
    """The mesh refused our public URL because it is not a private address.

    Raised as a distinct type so the agent can degrade to controller transport
    instead of treating a known policy boundary as an outage.
    """