mppi-agent 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mppi_agent/__init__.py ADDED
@@ -0,0 +1,53 @@
1
+ """MPPI agent payment and inference client."""
2
+
3
+ from mppi_protocol import (
4
+ Catalog,
5
+ Rates,
6
+ TokenCounts,
7
+ funding_amount,
8
+ parse_catalog,
9
+ required_coverage,
10
+ )
11
+ from mppi_protocol.signing import LocalSessionSigner
12
+
13
+ from .client import (
14
+ Client,
15
+ ClientError,
16
+ CloseAccountingError,
17
+ CompletionStream,
18
+ InferenceError,
19
+ PaymentError,
20
+ )
21
+ from .discovery import ProviderDiscovery, discover, verify_challenge
22
+ from .hooks import HookError, Hooks, ObserverStats
23
+ from .interfaces import AgentSessions, FundingWallet, OpenResult, SessionSigner
24
+ from .onboarding import OnboardingError, OnboardingResult, onboard
25
+
26
+ __all__ = [
27
+ "HookError",
28
+ "Hooks",
29
+ "ObserverStats",
30
+ "AgentSessions",
31
+ "Catalog",
32
+ "Client",
33
+ "ClientError",
34
+ "CloseAccountingError",
35
+ "CompletionStream",
36
+ "FundingWallet",
37
+ "LocalSessionSigner",
38
+ "InferenceError",
39
+ "OpenResult",
40
+ "OnboardingError",
41
+ "OnboardingResult",
42
+ "PaymentError",
43
+ "ProviderDiscovery",
44
+ "Rates",
45
+ "SessionSigner",
46
+ "TokenCounts",
47
+ "funding_amount",
48
+ "discover",
49
+ "parse_catalog",
50
+ "required_coverage",
51
+ "verify_challenge",
52
+ "onboard",
53
+ ]
@@ -0,0 +1,113 @@
1
+ """Agent-owned local intent journal; no keys, prompts or provider storage.
2
+
3
+ An exclusive lock protects one client's checkpoint for its lifetime. Writes
4
+ replace the complete record atomically after fsync, before economic submission.
5
+ Python's Unix flock and os.replace/fsync semantics are required (macOS/Linux).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import fcntl
11
+ import json
12
+ import os
13
+ import stat
14
+ import tempfile
15
+ from pathlib import Path
16
+ from typing import Any
17
+
18
+ from mppi_protocol.errors import ValidationCode, ValidationError
19
+
20
+ MAX_CHECKPOINT_BYTES = 64 << 20
21
+
22
+
23
+ def _invalid(message: str) -> ValidationError:
24
+ return ValidationError(ValidationCode.INVALID_VALUE, message)
25
+
26
+
27
+ def _unique(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
28
+ result: dict[str, Any] = {}
29
+ for key, value in pairs:
30
+ if key in result:
31
+ raise _invalid("duplicate checkpoint field")
32
+ result[key] = value
33
+ return result
34
+
35
+
36
+ class Checkpoint:
37
+ """One mode-0600, bounded, exclusively owned non-secret agent record."""
38
+
39
+ def __init__(self, path: Path) -> None:
40
+ self.path = Path(path).absolute()
41
+ self._lock: int | None = None
42
+ try:
43
+ self.path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
44
+ lock_path = self.path.with_name(self.path.name + ".lock")
45
+ fd = os.open(lock_path, os.O_RDWR | os.O_CREAT | os.O_NOFOLLOW, 0o600)
46
+ self._lock = fd
47
+ info = os.fstat(fd)
48
+ if not stat.S_ISREG(info.st_mode) or info.st_mode & 0o077:
49
+ raise _invalid("checkpoint lock permissions must be 0600")
50
+ fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
51
+ self.load()
52
+ except Exception:
53
+ self.close()
54
+ raise _invalid("checkpoint is unavailable, unsafe or already in use") from None
55
+
56
+ def load(self) -> dict[str, Any] | None:
57
+ if self._lock is None:
58
+ raise _invalid("checkpoint is closed")
59
+ try:
60
+ fd = os.open(self.path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
61
+ except FileNotFoundError:
62
+ return None
63
+ try:
64
+ with os.fdopen(fd, "rb") as source:
65
+ info = os.fstat(source.fileno())
66
+ if not stat.S_ISREG(info.st_mode) or info.st_mode & 0o077:
67
+ raise _invalid("checkpoint permissions must be 0600")
68
+ raw = source.read(MAX_CHECKPOINT_BYTES + 1)
69
+ if len(raw) > MAX_CHECKPOINT_BYTES:
70
+ raise _invalid("checkpoint exceeds its byte limit")
71
+ result = json.loads(raw.decode("utf-8"), object_pairs_hook=_unique)
72
+ if (
73
+ not isinstance(result, dict)
74
+ or type(result.get("version")) is not int
75
+ or result["version"] != 1
76
+ ):
77
+ raise _invalid("unsupported checkpoint record")
78
+ return result
79
+ except Exception:
80
+ raise _invalid("checkpoint cannot be validated") from None
81
+
82
+ def save(self, record: dict[str, Any]) -> None:
83
+ if self._lock is None or type(record.get("version")) is not int or record["version"] != 1:
84
+ raise _invalid("checkpoint is closed or has an invalid version")
85
+ raw = json.dumps(record, ensure_ascii=True, separators=(",", ":"), allow_nan=False).encode()
86
+ if len(raw) > MAX_CHECKPOINT_BYTES:
87
+ raise _invalid("checkpoint exceeds its byte limit")
88
+ temporary: str | None = None
89
+ try:
90
+ with tempfile.NamedTemporaryFile(
91
+ dir=self.path.parent, prefix="." + self.path.name, delete=False
92
+ ) as target:
93
+ temporary = target.name
94
+ target.write(raw)
95
+ target.flush()
96
+ os.fsync(target.fileno())
97
+ os.replace(temporary, self.path)
98
+ temporary = None
99
+ directory = os.open(self.path.parent, os.O_RDONLY | os.O_DIRECTORY)
100
+ try:
101
+ os.fsync(directory)
102
+ finally:
103
+ os.close(directory)
104
+ except Exception:
105
+ raise _invalid("checkpoint could not be durably written") from None
106
+ finally:
107
+ if temporary is not None:
108
+ os.unlink(temporary)
109
+
110
+ def close(self) -> None:
111
+ if self._lock is not None:
112
+ fd, self._lock = self._lock, None
113
+ os.close(fd)