pyb-agent-sdk 0.1.0__tar.gz
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.
- pyb_agent_sdk-0.1.0/PKG-INFO +23 -0
- pyb_agent_sdk-0.1.0/README.md +10 -0
- pyb_agent_sdk-0.1.0/pyproject.toml +25 -0
- pyb_agent_sdk-0.1.0/setup.cfg +4 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/__init__.py +87 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/agent_compaction.py +81 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/agent_hooks.py +107 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/agent_mcp.py +144 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/agent_session.py +536 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/client.py +285 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/permissions.py +216 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/protocol.py +219 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/protocol_session_backend.py +254 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/runtime_events.py +56 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk/transport.py +284 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk.egg-info/PKG-INFO +23 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk.egg-info/SOURCES.txt +27 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk.egg-info/dependency_links.txt +1 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk.egg-info/requires.txt +6 -0
- pyb_agent_sdk-0.1.0/src/pyb_agent_sdk.egg-info/top_level.txt +1 -0
- pyb_agent_sdk-0.1.0/tests/test_agent_session_contract.py +124 -0
- pyb_agent_sdk-0.1.0/tests/test_agent_session_p3_p5_guards.py +98 -0
- pyb_agent_sdk-0.1.0/tests/test_agent_session_p4_bridges.py +456 -0
- pyb_agent_sdk-0.1.0/tests/test_integration_serve.py +60 -0
- pyb_agent_sdk-0.1.0/tests/test_package_entry_contract.py +34 -0
- pyb_agent_sdk-0.1.0/tests/test_permission_updated_input.py +100 -0
- pyb_agent_sdk-0.1.0/tests/test_protocol_contract.py +142 -0
- pyb_agent_sdk-0.1.0/tests/test_protocol_session_backend.py +124 -0
- pyb_agent_sdk-0.1.0/tests/test_transport_client.py +410 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyb-agent-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Protocol-first Python skeleton for PYB Agent SDK
|
|
5
|
+
Author: PYB-XC
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: httpx>=0.27
|
|
9
|
+
Requires-Dist: websockets>=12.0
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
12
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
|
|
13
|
+
|
|
14
|
+
# PYB Agent SDK Python
|
|
15
|
+
|
|
16
|
+
Protocol-first Python skeleton for the PYB Agent SDK.
|
|
17
|
+
|
|
18
|
+
Current scope:
|
|
19
|
+
|
|
20
|
+
- `AgentSession` main entry skeleton
|
|
21
|
+
- `ProtocolSessionBackend`
|
|
22
|
+
- runtime event projection
|
|
23
|
+
- protocol honesty boundaries for unimplemented bridges
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyb-agent-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Protocol-first Python skeleton for PYB Agent SDK"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
authors = [{ name = "PYB-XC" }]
|
|
12
|
+
dependencies = ["httpx>=0.27", "websockets>=12.0"]
|
|
13
|
+
|
|
14
|
+
[project.optional-dependencies]
|
|
15
|
+
dev = ["pytest>=8.0", "pytest-asyncio>=0.24"]
|
|
16
|
+
|
|
17
|
+
[tool.pytest.ini_options]
|
|
18
|
+
asyncio_mode = "auto"
|
|
19
|
+
testpaths = ["tests"]
|
|
20
|
+
|
|
21
|
+
[tool.setuptools]
|
|
22
|
+
package-dir = {"" = "src"}
|
|
23
|
+
|
|
24
|
+
[tool.setuptools.packages.find]
|
|
25
|
+
where = ["src"]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from .agent_compaction import (
|
|
2
|
+
AgentCompactionAdapter,
|
|
3
|
+
AgentCompactionEvent,
|
|
4
|
+
AgentCompactionState,
|
|
5
|
+
create_agent_compaction_adapter,
|
|
6
|
+
)
|
|
7
|
+
from .agent_hooks import (
|
|
8
|
+
AGENT_HOOK_EVENT_NAMES,
|
|
9
|
+
AGENT_HOOK_TYPES,
|
|
10
|
+
AgentHookAdapter,
|
|
11
|
+
AgentSubagentLifecycleEvent,
|
|
12
|
+
create_agent_hook_adapter,
|
|
13
|
+
)
|
|
14
|
+
from .agent_mcp import (
|
|
15
|
+
AgentMcpAdapter,
|
|
16
|
+
AgentMcpCapabilityState,
|
|
17
|
+
AgentMcpEvent,
|
|
18
|
+
create_agent_mcp_adapter,
|
|
19
|
+
create_default_mcp_adapter_from_pyb_client,
|
|
20
|
+
)
|
|
21
|
+
from .agent_session import (
|
|
22
|
+
AgentSession,
|
|
23
|
+
AgentSessionInput,
|
|
24
|
+
CreateAgentSessionOptions,
|
|
25
|
+
QueryOnceResult,
|
|
26
|
+
create_agent_session,
|
|
27
|
+
query_once,
|
|
28
|
+
)
|
|
29
|
+
from .client import ClientOptions, PybAgentClient, SessionLostError
|
|
30
|
+
from .permissions import OnPermissionLost, PermissionManager, PermissionRequest
|
|
31
|
+
from .protocol import (
|
|
32
|
+
ProtocolError,
|
|
33
|
+
ServerMessage,
|
|
34
|
+
decode_envelope,
|
|
35
|
+
decode_server_message,
|
|
36
|
+
encode_client_message,
|
|
37
|
+
)
|
|
38
|
+
from .protocol_session_backend import (
|
|
39
|
+
DefaultProtocolSessionClient,
|
|
40
|
+
DefaultSSEClient,
|
|
41
|
+
ProtocolSessionBackend,
|
|
42
|
+
create_protocol_session_backend,
|
|
43
|
+
)
|
|
44
|
+
from .runtime_events import RuntimeEvent, RuntimeEventDomain, project_legacy_event_to_runtime_event
|
|
45
|
+
from .transport import HybridTransport, TransportConfig
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"AgentCompactionState",
|
|
49
|
+
"AgentCompactionAdapter",
|
|
50
|
+
"AgentCompactionEvent",
|
|
51
|
+
"AGENT_HOOK_EVENT_NAMES",
|
|
52
|
+
"AGENT_HOOK_TYPES",
|
|
53
|
+
"AgentHookAdapter",
|
|
54
|
+
"AgentMcpAdapter",
|
|
55
|
+
"AgentMcpCapabilityState",
|
|
56
|
+
"AgentMcpEvent",
|
|
57
|
+
"AgentSession",
|
|
58
|
+
"AgentSessionInput",
|
|
59
|
+
"AgentSubagentLifecycleEvent",
|
|
60
|
+
"ClientOptions",
|
|
61
|
+
"CreateAgentSessionOptions",
|
|
62
|
+
"DefaultProtocolSessionClient",
|
|
63
|
+
"DefaultSSEClient",
|
|
64
|
+
"ProtocolSessionBackend",
|
|
65
|
+
"ProtocolError",
|
|
66
|
+
"PermissionManager",
|
|
67
|
+
"PermissionRequest",
|
|
68
|
+
"PybAgentClient",
|
|
69
|
+
"SessionLostError",
|
|
70
|
+
"OnPermissionLost",
|
|
71
|
+
"HybridTransport",
|
|
72
|
+
"TransportConfig",
|
|
73
|
+
"QueryOnceResult",
|
|
74
|
+
"RuntimeEvent",
|
|
75
|
+
"RuntimeEventDomain",
|
|
76
|
+
"create_agent_session",
|
|
77
|
+
"create_agent_compaction_adapter",
|
|
78
|
+
"create_agent_hook_adapter",
|
|
79
|
+
"create_agent_mcp_adapter",
|
|
80
|
+
"create_default_mcp_adapter_from_pyb_client",
|
|
81
|
+
"create_protocol_session_backend",
|
|
82
|
+
"decode_envelope",
|
|
83
|
+
"decode_server_message",
|
|
84
|
+
"encode_client_message",
|
|
85
|
+
"project_legacy_event_to_runtime_event",
|
|
86
|
+
"query_once",
|
|
87
|
+
]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Callable, Protocol
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(slots=True)
|
|
8
|
+
class AgentCompactionState:
|
|
9
|
+
mode: str | None = None
|
|
10
|
+
trigger_strategy: str | None = None
|
|
11
|
+
summary_present: bool = False
|
|
12
|
+
has_restore_seeds: bool = False
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(slots=True)
|
|
16
|
+
class AgentCompactionEvent:
|
|
17
|
+
type: str
|
|
18
|
+
session_id: str
|
|
19
|
+
timestamp: float
|
|
20
|
+
data: dict[str, object]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AgentCompactionAdapter(Protocol):
|
|
24
|
+
def get_state(self) -> object: ...
|
|
25
|
+
|
|
26
|
+
def get_summary(self) -> object: ...
|
|
27
|
+
|
|
28
|
+
async def compact(self, input_data: dict[str, object] | None = None) -> object: ...
|
|
29
|
+
|
|
30
|
+
def subscribe(
|
|
31
|
+
self,
|
|
32
|
+
listener: Callable[[AgentCompactionEvent], None],
|
|
33
|
+
) -> Callable[[], None]: ...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class _AgentCompactionAdapter:
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
*,
|
|
40
|
+
get_state: Callable[[], object],
|
|
41
|
+
get_summary: Callable[[], object],
|
|
42
|
+
compact: Callable[[dict[str, object] | None], object],
|
|
43
|
+
subscribe: Callable[[Callable[[AgentCompactionEvent], None]], Callable[[], None]],
|
|
44
|
+
) -> None:
|
|
45
|
+
self._get_state = get_state
|
|
46
|
+
self._get_summary = get_summary
|
|
47
|
+
self._compact = compact
|
|
48
|
+
self._subscribe = subscribe
|
|
49
|
+
|
|
50
|
+
def get_state(self) -> object:
|
|
51
|
+
return self._get_state()
|
|
52
|
+
|
|
53
|
+
def get_summary(self) -> object:
|
|
54
|
+
return self._get_summary()
|
|
55
|
+
|
|
56
|
+
async def compact(self, input_data: dict[str, object] | None = None) -> object:
|
|
57
|
+
result = self._compact(input_data)
|
|
58
|
+
if hasattr(result, "__await__"):
|
|
59
|
+
return await result # type: ignore[misc]
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
def subscribe(
|
|
63
|
+
self,
|
|
64
|
+
listener: Callable[[AgentCompactionEvent], None],
|
|
65
|
+
) -> Callable[[], None]:
|
|
66
|
+
return self._subscribe(listener)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def create_agent_compaction_adapter(
|
|
70
|
+
*,
|
|
71
|
+
get_state: Callable[[], object],
|
|
72
|
+
get_summary: Callable[[], object],
|
|
73
|
+
compact: Callable[[dict[str, object] | None], object],
|
|
74
|
+
subscribe: Callable[[Callable[[AgentCompactionEvent], None]], Callable[[], None]],
|
|
75
|
+
) -> AgentCompactionAdapter:
|
|
76
|
+
return _AgentCompactionAdapter(
|
|
77
|
+
get_state=get_state,
|
|
78
|
+
get_summary=get_summary,
|
|
79
|
+
compact=compact,
|
|
80
|
+
subscribe=subscribe,
|
|
81
|
+
)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Callable, Literal, Protocol, Sequence
|
|
5
|
+
|
|
6
|
+
AGENT_HOOK_EVENT_NAMES = {
|
|
7
|
+
"PreToolUse",
|
|
8
|
+
"PostToolUse",
|
|
9
|
+
"PostToolUseFailure",
|
|
10
|
+
"PermissionRequest",
|
|
11
|
+
"PermissionDenied",
|
|
12
|
+
"SessionStart",
|
|
13
|
+
"SessionEnd",
|
|
14
|
+
"UserPromptSubmit",
|
|
15
|
+
"Stop",
|
|
16
|
+
"PreCompact",
|
|
17
|
+
"PostCompact",
|
|
18
|
+
"Elicitation",
|
|
19
|
+
"ElicitationResult",
|
|
20
|
+
"Notification",
|
|
21
|
+
"SubagentStart",
|
|
22
|
+
"SubagentStop",
|
|
23
|
+
"ConfigChange",
|
|
24
|
+
}
|
|
25
|
+
AGENT_HOOK_TYPES = {"command", "prompt"}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
AgentHookType = Literal["command", "prompt"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(slots=True)
|
|
32
|
+
class AgentSubagentLifecycleEvent:
|
|
33
|
+
type: str
|
|
34
|
+
session_id: str
|
|
35
|
+
timestamp: float
|
|
36
|
+
data: dict[str, object]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AgentHookAdapter(Protocol):
|
|
40
|
+
def register_hooks(self, hooks: Sequence[dict[str, object]]) -> None: ...
|
|
41
|
+
|
|
42
|
+
def get_runtime_state(self) -> object: ...
|
|
43
|
+
|
|
44
|
+
def subscribe_subagent_lifecycle(
|
|
45
|
+
self,
|
|
46
|
+
listener: Callable[[AgentSubagentLifecycleEvent], None],
|
|
47
|
+
) -> Callable[[], None]: ...
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class _AgentHookAdapter:
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
*,
|
|
54
|
+
register_hooks: Callable[[Sequence[dict[str, object]]], None] | None = None,
|
|
55
|
+
get_runtime_state: Callable[[], object] | None = None,
|
|
56
|
+
subscribe_subagent_lifecycle: Callable[
|
|
57
|
+
[Callable[[AgentSubagentLifecycleEvent], None]], Callable[[], None]
|
|
58
|
+
]
|
|
59
|
+
| None = None,
|
|
60
|
+
) -> None:
|
|
61
|
+
self._register_hooks = register_hooks
|
|
62
|
+
self._get_runtime_state = get_runtime_state
|
|
63
|
+
self._subscribe_subagent_lifecycle = subscribe_subagent_lifecycle
|
|
64
|
+
|
|
65
|
+
def register_hooks(self, hooks: Sequence[dict[str, object]]) -> None:
|
|
66
|
+
if self._register_hooks is None:
|
|
67
|
+
return
|
|
68
|
+
self._register_hooks(hooks)
|
|
69
|
+
|
|
70
|
+
def get_runtime_state(self) -> object:
|
|
71
|
+
if self._get_runtime_state is None:
|
|
72
|
+
return None
|
|
73
|
+
return self._get_runtime_state()
|
|
74
|
+
|
|
75
|
+
def subscribe_subagent_lifecycle(
|
|
76
|
+
self,
|
|
77
|
+
listener: Callable[[AgentSubagentLifecycleEvent], None],
|
|
78
|
+
) -> Callable[[], None]:
|
|
79
|
+
if self._subscribe_subagent_lifecycle is None:
|
|
80
|
+
return lambda: None
|
|
81
|
+
return self._subscribe_subagent_lifecycle(listener)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def create_agent_hook_adapter(
|
|
85
|
+
*,
|
|
86
|
+
register_hooks: Callable[[Sequence[dict[str, object]]], None] | None = None,
|
|
87
|
+
get_runtime_state: Callable[[], object] | None = None,
|
|
88
|
+
subscribe_subagent_lifecycle: Callable[
|
|
89
|
+
[Callable[[AgentSubagentLifecycleEvent], None]], Callable[[], None]
|
|
90
|
+
]
|
|
91
|
+
| None = None,
|
|
92
|
+
) -> AgentHookAdapter:
|
|
93
|
+
return _AgentHookAdapter(
|
|
94
|
+
register_hooks=register_hooks,
|
|
95
|
+
get_runtime_state=get_runtime_state,
|
|
96
|
+
subscribe_subagent_lifecycle=subscribe_subagent_lifecycle,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def validate_hook_descriptors(hooks: Sequence[dict[str, object]]) -> None:
|
|
101
|
+
for hook in hooks:
|
|
102
|
+
hook_type = hook.get("type")
|
|
103
|
+
hook_event = hook.get("event")
|
|
104
|
+
if hook_type not in AGENT_HOOK_TYPES:
|
|
105
|
+
raise RuntimeError("AGENT_SESSION_HOOK_TYPE_UNSUPPORTED")
|
|
106
|
+
if hook_event not in AGENT_HOOK_EVENT_NAMES:
|
|
107
|
+
raise RuntimeError("AGENT_SESSION_HOOK_EVENT_UNSUPPORTED")
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Callable, Protocol
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(slots=True)
|
|
8
|
+
class AgentMcpCapabilityState:
|
|
9
|
+
servers: list[dict[str, object]] = field(default_factory=list)
|
|
10
|
+
capabilities: list[dict[str, object]] = field(default_factory=list)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(slots=True)
|
|
14
|
+
class AgentMcpEvent:
|
|
15
|
+
type: str
|
|
16
|
+
session_id: str
|
|
17
|
+
timestamp: float
|
|
18
|
+
data: dict[str, object]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AgentMcpAdapter(Protocol):
|
|
22
|
+
async def list_servers(self) -> object: ...
|
|
23
|
+
|
|
24
|
+
async def connect_server(self, server_id: str) -> object: ...
|
|
25
|
+
|
|
26
|
+
async def disconnect_server(self, server_id: str) -> object: ...
|
|
27
|
+
|
|
28
|
+
async def reconnect_server(self, server_id: str) -> object: ...
|
|
29
|
+
|
|
30
|
+
def get_capability_state(self) -> object: ...
|
|
31
|
+
|
|
32
|
+
def get_semantic_state(self) -> object: ...
|
|
33
|
+
|
|
34
|
+
def get_deep_runtime_state(self) -> object: ...
|
|
35
|
+
|
|
36
|
+
def subscribe(
|
|
37
|
+
self,
|
|
38
|
+
listener: Callable[[AgentMcpEvent], None],
|
|
39
|
+
) -> Callable[[], None]: ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class _AgentMcpAdapter:
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
*,
|
|
46
|
+
list_servers: Callable[[], object],
|
|
47
|
+
connect_server: Callable[[str], object],
|
|
48
|
+
disconnect_server: Callable[[str], object],
|
|
49
|
+
reconnect_server: Callable[[str], object] | None = None,
|
|
50
|
+
get_capability_state: Callable[[], object] | None = None,
|
|
51
|
+
get_semantic_state: Callable[[], object] | None = None,
|
|
52
|
+
get_deep_runtime_state: Callable[[], object] | None = None,
|
|
53
|
+
subscribe: Callable[[Callable[[AgentMcpEvent], None]], Callable[[], None]] | None = None,
|
|
54
|
+
) -> None:
|
|
55
|
+
self._list_servers = list_servers
|
|
56
|
+
self._connect_server = connect_server
|
|
57
|
+
self._disconnect_server = disconnect_server
|
|
58
|
+
self._reconnect_server = reconnect_server
|
|
59
|
+
self._get_capability_state = get_capability_state
|
|
60
|
+
self._get_semantic_state = get_semantic_state
|
|
61
|
+
self._get_deep_runtime_state = get_deep_runtime_state
|
|
62
|
+
self._subscribe = subscribe
|
|
63
|
+
|
|
64
|
+
async def list_servers(self) -> object:
|
|
65
|
+
return await _maybe_await(self._list_servers())
|
|
66
|
+
|
|
67
|
+
async def connect_server(self, server_id: str) -> object:
|
|
68
|
+
return await _maybe_await(self._connect_server(server_id))
|
|
69
|
+
|
|
70
|
+
async def disconnect_server(self, server_id: str) -> object:
|
|
71
|
+
return await _maybe_await(self._disconnect_server(server_id))
|
|
72
|
+
|
|
73
|
+
async def reconnect_server(self, server_id: str) -> object:
|
|
74
|
+
if self._reconnect_server is None:
|
|
75
|
+
raise RuntimeError("AGENT_SESSION_MCP_RECONNECT_UNAVAILABLE")
|
|
76
|
+
return await _maybe_await(self._reconnect_server(server_id))
|
|
77
|
+
|
|
78
|
+
def get_capability_state(self) -> object:
|
|
79
|
+
if self._get_capability_state is None:
|
|
80
|
+
return None
|
|
81
|
+
return self._get_capability_state()
|
|
82
|
+
|
|
83
|
+
def get_semantic_state(self) -> object:
|
|
84
|
+
if self._get_semantic_state is None:
|
|
85
|
+
return None
|
|
86
|
+
return self._get_semantic_state()
|
|
87
|
+
|
|
88
|
+
def get_deep_runtime_state(self) -> object:
|
|
89
|
+
if self._get_deep_runtime_state is None:
|
|
90
|
+
return None
|
|
91
|
+
return self._get_deep_runtime_state()
|
|
92
|
+
|
|
93
|
+
def subscribe(
|
|
94
|
+
self,
|
|
95
|
+
listener: Callable[[AgentMcpEvent], None],
|
|
96
|
+
) -> Callable[[], None]:
|
|
97
|
+
if self._subscribe is None:
|
|
98
|
+
return lambda: None
|
|
99
|
+
return self._subscribe(listener)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def create_agent_mcp_adapter(
|
|
103
|
+
*,
|
|
104
|
+
list_servers: Callable[[], object],
|
|
105
|
+
connect_server: Callable[[str], object],
|
|
106
|
+
disconnect_server: Callable[[str], object],
|
|
107
|
+
reconnect_server: Callable[[str], object] | None = None,
|
|
108
|
+
get_capability_state: Callable[[], object] | None = None,
|
|
109
|
+
get_semantic_state: Callable[[], object] | None = None,
|
|
110
|
+
get_deep_runtime_state: Callable[[], object] | None = None,
|
|
111
|
+
subscribe: Callable[[Callable[[AgentMcpEvent], None]], Callable[[], None]] | None = None,
|
|
112
|
+
) -> AgentMcpAdapter:
|
|
113
|
+
return _AgentMcpAdapter(
|
|
114
|
+
list_servers=list_servers,
|
|
115
|
+
connect_server=connect_server,
|
|
116
|
+
disconnect_server=disconnect_server,
|
|
117
|
+
reconnect_server=reconnect_server,
|
|
118
|
+
get_capability_state=get_capability_state,
|
|
119
|
+
get_semantic_state=get_semantic_state,
|
|
120
|
+
get_deep_runtime_state=get_deep_runtime_state,
|
|
121
|
+
subscribe=subscribe,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def create_default_mcp_adapter_from_pyb_client(pyb_client: object | None) -> AgentMcpAdapter | None:
|
|
126
|
+
mcp = getattr(pyb_client, "mcp", None) if pyb_client is not None else None
|
|
127
|
+
if mcp is None:
|
|
128
|
+
return None
|
|
129
|
+
if not all(hasattr(mcp, name) for name in ("list", "connect", "disconnect")):
|
|
130
|
+
return None
|
|
131
|
+
return create_agent_mcp_adapter(
|
|
132
|
+
list_servers=lambda: mcp.list(),
|
|
133
|
+
connect_server=lambda server_id: mcp.connect(server_id),
|
|
134
|
+
disconnect_server=lambda server_id: mcp.disconnect(server_id),
|
|
135
|
+
reconnect_server=(lambda server_id: mcp.reconnect(server_id))
|
|
136
|
+
if hasattr(mcp, "reconnect")
|
|
137
|
+
else None,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
async def _maybe_await(value: object) -> object:
|
|
142
|
+
if hasattr(value, "__await__"):
|
|
143
|
+
return await value # type: ignore[misc]
|
|
144
|
+
return value
|