macp-sdk-python 0.2.1__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.
- macp_sdk/__init__.py +207 -0
- macp_sdk/_logging.py +16 -0
- macp_sdk/agent/__init__.py +64 -0
- macp_sdk/agent/dispatcher.py +105 -0
- macp_sdk/agent/participant.py +404 -0
- macp_sdk/agent/runner.py +100 -0
- macp_sdk/agent/strategies.py +312 -0
- macp_sdk/agent/transports.py +153 -0
- macp_sdk/agent/types.py +64 -0
- macp_sdk/auth.py +74 -0
- macp_sdk/base_projection.py +52 -0
- macp_sdk/base_session.py +169 -0
- macp_sdk/client.py +625 -0
- macp_sdk/constants.py +20 -0
- macp_sdk/decision.py +154 -0
- macp_sdk/envelope.py +180 -0
- macp_sdk/errors.py +101 -0
- macp_sdk/handoff.py +241 -0
- macp_sdk/policy.py +292 -0
- macp_sdk/projections.py +183 -0
- macp_sdk/proposal.py +305 -0
- macp_sdk/proto_registry.py +150 -0
- macp_sdk/py.typed +0 -0
- macp_sdk/quorum.py +258 -0
- macp_sdk/retry.py +64 -0
- macp_sdk/task.py +368 -0
- macp_sdk/validation.py +117 -0
- macp_sdk/watchers.py +122 -0
- macp_sdk_python-0.2.1.dist-info/METADATA +165 -0
- macp_sdk_python-0.2.1.dist-info/RECORD +33 -0
- macp_sdk_python-0.2.1.dist-info/WHEEL +5 -0
- macp_sdk_python-0.2.1.dist-info/licenses/LICENSE +201 -0
- macp_sdk_python-0.2.1.dist-info/top_level.txt +1 -0
macp_sdk/base_session.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Iterable, Mapping
|
|
5
|
+
from typing import Any, ClassVar
|
|
6
|
+
|
|
7
|
+
from macp.v1 import core_pb2, envelope_pb2
|
|
8
|
+
|
|
9
|
+
from ._logging import logger
|
|
10
|
+
from .auth import AuthConfig
|
|
11
|
+
from .base_projection import BaseProjection
|
|
12
|
+
from .client import MacpClient, MacpStream
|
|
13
|
+
from .constants import (
|
|
14
|
+
DEFAULT_CONFIGURATION_VERSION,
|
|
15
|
+
DEFAULT_MODE_VERSION,
|
|
16
|
+
DEFAULT_POLICY_VERSION,
|
|
17
|
+
)
|
|
18
|
+
from .envelope import (
|
|
19
|
+
build_commitment_payload,
|
|
20
|
+
build_envelope,
|
|
21
|
+
build_session_start_payload,
|
|
22
|
+
new_session_id,
|
|
23
|
+
serialize_message,
|
|
24
|
+
)
|
|
25
|
+
from .errors import MacpIdentityMismatchError
|
|
26
|
+
from .validation import validate_participant_count, validate_session_id
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class BaseSession(ABC):
|
|
30
|
+
"""Abstract base for mode session helpers.
|
|
31
|
+
|
|
32
|
+
Provides shared logic for session lifecycle (start, commit, cancel,
|
|
33
|
+
metadata, streaming) so that mode-specific subclasses only need to
|
|
34
|
+
implement their own action methods.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
MODE: ClassVar[str]
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
client: MacpClient,
|
|
42
|
+
*,
|
|
43
|
+
session_id: str | None = None,
|
|
44
|
+
mode_version: str = DEFAULT_MODE_VERSION,
|
|
45
|
+
configuration_version: str = DEFAULT_CONFIGURATION_VERSION,
|
|
46
|
+
policy_version: str = DEFAULT_POLICY_VERSION,
|
|
47
|
+
auth: AuthConfig | None = None,
|
|
48
|
+
) -> None:
|
|
49
|
+
self.client = client
|
|
50
|
+
self.session_id = session_id or new_session_id()
|
|
51
|
+
if session_id:
|
|
52
|
+
validate_session_id(session_id)
|
|
53
|
+
self.mode_version = mode_version
|
|
54
|
+
self.configuration_version = configuration_version
|
|
55
|
+
self.policy_version = policy_version
|
|
56
|
+
self.auth = auth
|
|
57
|
+
self.projection = self._create_projection()
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def _create_projection(self) -> BaseProjection:
|
|
61
|
+
"""Return a new projection instance for this mode."""
|
|
62
|
+
|
|
63
|
+
def _sender_for(self, sender: str | None, *, auth: AuthConfig | None = None) -> str:
|
|
64
|
+
auth_cfg = auth or self.auth or self.client.auth
|
|
65
|
+
expected = auth_cfg.expected_sender if auth_cfg else None
|
|
66
|
+
if sender:
|
|
67
|
+
if expected is not None and sender != expected:
|
|
68
|
+
raise MacpIdentityMismatchError(expected=expected, actual=sender)
|
|
69
|
+
return sender
|
|
70
|
+
return auth_cfg.sender or "" if auth_cfg else ""
|
|
71
|
+
|
|
72
|
+
def _send_and_track(
|
|
73
|
+
self,
|
|
74
|
+
envelope: envelope_pb2.Envelope,
|
|
75
|
+
*,
|
|
76
|
+
auth: AuthConfig | None = None,
|
|
77
|
+
) -> envelope_pb2.Ack:
|
|
78
|
+
logger.debug(
|
|
79
|
+
"send session=%s type=%s sender=%s",
|
|
80
|
+
envelope.session_id,
|
|
81
|
+
envelope.message_type,
|
|
82
|
+
envelope.sender,
|
|
83
|
+
)
|
|
84
|
+
ack = self.client.send(envelope, auth=auth or self.auth)
|
|
85
|
+
if ack.ok:
|
|
86
|
+
self.projection.apply_envelope(envelope)
|
|
87
|
+
else:
|
|
88
|
+
logger.warning(
|
|
89
|
+
"nack session=%s type=%s code=%s",
|
|
90
|
+
envelope.session_id,
|
|
91
|
+
envelope.message_type,
|
|
92
|
+
getattr(ack, "error", None),
|
|
93
|
+
)
|
|
94
|
+
return ack
|
|
95
|
+
|
|
96
|
+
def start(
|
|
97
|
+
self,
|
|
98
|
+
*,
|
|
99
|
+
intent: str,
|
|
100
|
+
participants: list[str],
|
|
101
|
+
ttl_ms: int,
|
|
102
|
+
context: bytes | str | Mapping[str, object] | None = None,
|
|
103
|
+
roots: Iterable[Any] | None = None,
|
|
104
|
+
sender: str | None = None,
|
|
105
|
+
auth: AuthConfig | None = None,
|
|
106
|
+
) -> envelope_pb2.Ack:
|
|
107
|
+
"""Send SessionStart and begin tracking via the projection."""
|
|
108
|
+
validate_participant_count(len(participants))
|
|
109
|
+
payload = build_session_start_payload(
|
|
110
|
+
intent=intent,
|
|
111
|
+
participants=participants,
|
|
112
|
+
ttl_ms=ttl_ms,
|
|
113
|
+
mode_version=self.mode_version,
|
|
114
|
+
configuration_version=self.configuration_version,
|
|
115
|
+
policy_version=self.policy_version,
|
|
116
|
+
context=context,
|
|
117
|
+
roots=roots,
|
|
118
|
+
)
|
|
119
|
+
envelope = build_envelope(
|
|
120
|
+
mode=self.MODE,
|
|
121
|
+
message_type="SessionStart",
|
|
122
|
+
session_id=self.session_id,
|
|
123
|
+
sender=self._sender_for(sender, auth=auth),
|
|
124
|
+
payload=serialize_message(payload),
|
|
125
|
+
)
|
|
126
|
+
return self._send_and_track(envelope, auth=auth or self.auth)
|
|
127
|
+
|
|
128
|
+
def commit(
|
|
129
|
+
self,
|
|
130
|
+
*,
|
|
131
|
+
action: str,
|
|
132
|
+
authority_scope: str,
|
|
133
|
+
reason: str,
|
|
134
|
+
commitment_id: str | None = None,
|
|
135
|
+
outcome_positive: bool | None = None,
|
|
136
|
+
sender: str | None = None,
|
|
137
|
+
auth: AuthConfig | None = None,
|
|
138
|
+
) -> envelope_pb2.Ack:
|
|
139
|
+
"""Send Commitment to resolve the session."""
|
|
140
|
+
payload = build_commitment_payload(
|
|
141
|
+
action=action,
|
|
142
|
+
authority_scope=authority_scope,
|
|
143
|
+
reason=reason,
|
|
144
|
+
commitment_id=commitment_id,
|
|
145
|
+
mode_version=self.mode_version,
|
|
146
|
+
configuration_version=self.configuration_version,
|
|
147
|
+
policy_version=self.policy_version,
|
|
148
|
+
outcome_positive=outcome_positive,
|
|
149
|
+
)
|
|
150
|
+
envelope = build_envelope(
|
|
151
|
+
mode=self.MODE,
|
|
152
|
+
message_type="Commitment",
|
|
153
|
+
session_id=self.session_id,
|
|
154
|
+
sender=self._sender_for(sender, auth=auth),
|
|
155
|
+
payload=serialize_message(payload),
|
|
156
|
+
)
|
|
157
|
+
return self._send_and_track(envelope, auth=auth)
|
|
158
|
+
|
|
159
|
+
def metadata(self, *, auth: AuthConfig | None = None) -> core_pb2.GetSessionResponse:
|
|
160
|
+
"""Query session metadata from the runtime."""
|
|
161
|
+
return self.client.get_session(self.session_id, auth=auth or self.auth)
|
|
162
|
+
|
|
163
|
+
def cancel(self, *, reason: str = "", auth: AuthConfig | None = None) -> envelope_pb2.Ack:
|
|
164
|
+
"""Cancel the session."""
|
|
165
|
+
return self.client.cancel_session(self.session_id, reason=reason, auth=auth or self.auth)
|
|
166
|
+
|
|
167
|
+
def open_stream(self, *, auth: AuthConfig | None = None) -> MacpStream:
|
|
168
|
+
"""Open a bidirectional stream for this session."""
|
|
169
|
+
return self.client.open_stream(auth=auth or self.auth)
|