attp-client 0.0.8__tar.gz → 0.0.10__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.
- {attp_client-0.0.8 → attp_client-0.0.10}/PKG-INFO +2 -2
- {attp_client-0.0.8 → attp_client-0.0.10}/pyproject.toml +2 -2
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/catalog.py +9 -2
- attp_client-0.0.10/src/attp_client/client.py +207 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/inference.py +73 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/session.py +11 -2
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/tools.py +1 -1
- attp_client-0.0.10/src/attp_client/utils/envelopizer.py +9 -0
- attp_client-0.0.8/src/attp_client/client.py +0 -119
- {attp_client-0.0.8 → attp_client-0.0.10}/README.md +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/__init__.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/consts.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/errors/attp_exception.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/errors/correlated_rpc_exception.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/errors/dead_session.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/errors/not_found.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/errors/serialization_error.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/errors/unauthenticated_error.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/catalogs/catalog.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/catalogs/tools/envelope.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/error.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/handshake/auth.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/handshake/hello.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/handshake/ready.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/inference/enums/message_data_type.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/inference/enums/message_emergency_type.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/inference/enums/message_type.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/inference/message.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/inference/tool.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/route_mappings.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/misc/fixed_basemodel.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/misc/serializable.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/router.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/types/route_mapping.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/utils/context_awaiter.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/utils/route_mapper.py +0 -0
- {attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/utils/serializer.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: attp-client
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.10
|
4
4
|
Summary: A python-sdk client for interacting with AgentHub's ATTP protocol (Agent Tool Transport Protocol)
|
5
5
|
License: MIT
|
6
6
|
Author: Ascender Team
|
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
12
12
|
Classifier: Programming Language :: Python :: 3.13
|
13
13
|
Requires-Dist: ascender-framework (>=2.0rc7,<3.0)
|
14
|
-
Requires-Dist: attp-core (==0.1.
|
14
|
+
Requires-Dist: attp-core (==0.1.13)
|
15
15
|
Requires-Dist: msgpack (>=1.1.1,<2.0.0)
|
16
16
|
Requires-Dist: pydantic (>=2.11.7,<3.0.0)
|
17
17
|
Description-Content-Type: text/markdown
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "attp-client"
|
3
|
-
version = "0.0.
|
3
|
+
version = "0.0.10"
|
4
4
|
description = "A python-sdk client for interacting with AgentHub's ATTP protocol (Agent Tool Transport Protocol)"
|
5
5
|
authors = [
|
6
6
|
{name = "Ascender Team"}
|
@@ -10,7 +10,7 @@ readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11,<3.14"
|
11
11
|
dependencies = [
|
12
12
|
"pydantic (>=2.11.7,<3.0.0)",
|
13
|
-
"attp-core (==0.1.
|
13
|
+
"attp-core (==0.1.13)",
|
14
14
|
"msgpack (>=1.1.1,<2.0.0)",
|
15
15
|
"ascender-framework (>=2.0rc7,<3.0)"
|
16
16
|
]
|
@@ -28,6 +28,7 @@ class AttpCatalog:
|
|
28
28
|
self.tool_manager = manager
|
29
29
|
self.attached_tools = {}
|
30
30
|
self.tool_name_to_id_symlink = {}
|
31
|
+
self.disposable = None
|
31
32
|
|
32
33
|
self.responder = self.tool_manager.router.responder
|
33
34
|
|
@@ -59,14 +60,20 @@ class AttpCatalog:
|
|
59
60
|
from reactivex import empty
|
60
61
|
return empty()
|
61
62
|
|
62
|
-
self.responder.pipe(
|
63
|
-
ops.filter(lambda item: item.payload is not None and item.
|
63
|
+
self.disposable = self.responder.pipe(
|
64
|
+
ops.filter(lambda item: item.payload is not None and item.route_id == 2),
|
64
65
|
ops.map(lambda item: envelopize(item)),
|
65
66
|
ops.catch(catch_handler),
|
66
67
|
ops.filter(lambda item: item.catalog == self.catalog_name and item.tool_id in self.attached_tools),
|
67
68
|
ops.observe_on(scheduler),
|
68
69
|
).subscribe(lambda item: handle_call(item))
|
69
70
|
|
71
|
+
async def handle_callback(self, envelope: IEnvelope) -> Any:
|
72
|
+
if envelope.tool_id not in self.attached_tools:
|
73
|
+
raise NotFoundError(f"Tool {envelope.tool_id} not marked as registered and wasn't found in the catalog {self.catalog_name}.")
|
74
|
+
|
75
|
+
return await self.handle_call(envelope)
|
76
|
+
|
70
77
|
async def attach_tool(
|
71
78
|
self,
|
72
79
|
callback: Callable[[IEnvelope], Any],
|
@@ -0,0 +1,207 @@
|
|
1
|
+
import asyncio
|
2
|
+
from functools import cached_property
|
3
|
+
from logging import Logger, getLogger
|
4
|
+
from typing import Any, Callable
|
5
|
+
from attp_core.rs_api import AttpClientSession, Limits
|
6
|
+
from reactivex import Subject, operators as ops
|
7
|
+
from reactivex.scheduler.eventloop import AsyncIOScheduler
|
8
|
+
from attp_core.rs_api import PyAttpMessage
|
9
|
+
|
10
|
+
from attp_client.catalog import AttpCatalog
|
11
|
+
from attp_client.errors.dead_session import DeadSessionError
|
12
|
+
from attp_client.inference import AttpInferenceAPI
|
13
|
+
from attp_client.interfaces.catalogs.catalog import ICatalogResponse
|
14
|
+
from attp_client.interfaces.error import IErr
|
15
|
+
from attp_client.misc.serializable import Serializable
|
16
|
+
from attp_client.router import AttpRouter
|
17
|
+
from attp_client.session import SessionDriver
|
18
|
+
from attp_client.tools import ToolsManager
|
19
|
+
from attp_client.types.route_mapping import AttpRouteMapping, RouteType
|
20
|
+
from attp_client.utils import envelopizer
|
21
|
+
|
22
|
+
from attp_core.rs_api import AttpCommand
|
23
|
+
|
24
|
+
class ATTPClient:
|
25
|
+
|
26
|
+
is_connected: bool
|
27
|
+
client: AttpClientSession
|
28
|
+
session: SessionDriver | None
|
29
|
+
routes: list[AttpRouteMapping]
|
30
|
+
inference: AttpInferenceAPI
|
31
|
+
catalogs: list[AttpCatalog]
|
32
|
+
|
33
|
+
def __init__(
|
34
|
+
self,
|
35
|
+
agt_token: str,
|
36
|
+
organization_id: int,
|
37
|
+
*,
|
38
|
+
connection_url: str | None = None,
|
39
|
+
max_retries: int = 20,
|
40
|
+
limits: Limits | None = None,
|
41
|
+
logger: Logger | None = None
|
42
|
+
):
|
43
|
+
self.__agt_token = agt_token
|
44
|
+
self.organization_id = organization_id
|
45
|
+
self.connection_url = connection_url or "attp://localhost:6563"
|
46
|
+
|
47
|
+
self.session = None
|
48
|
+
self.max_retries = max_retries
|
49
|
+
self.limits = limits or Limits(max_payload_size=50000)
|
50
|
+
self.client = AttpClientSession(self.connection_url, limits=self.limits)
|
51
|
+
self.logger = logger
|
52
|
+
|
53
|
+
self.route_increment_index = 2
|
54
|
+
|
55
|
+
self.responder = Subject[PyAttpMessage]()
|
56
|
+
self.routes = []
|
57
|
+
self.catalogs = []
|
58
|
+
self.disposable = None
|
59
|
+
|
60
|
+
async def connect(self):
|
61
|
+
# Open the connection
|
62
|
+
client = await self.client.connect(self.max_retries)
|
63
|
+
|
64
|
+
if not client.session:
|
65
|
+
raise ConnectionError("Failed to connect to ATTP server after 10 attempts!")
|
66
|
+
|
67
|
+
self.session = SessionDriver(
|
68
|
+
client.session,
|
69
|
+
agt_token=self.__agt_token,
|
70
|
+
organization_id=self.organization_id,
|
71
|
+
# route_mappings=self.routes,
|
72
|
+
logger=self.logger or getLogger("Ascender Framework")
|
73
|
+
)
|
74
|
+
asyncio.create_task(self.session.start_listener())
|
75
|
+
# Send an authentication frame as soon as connection estabilishes with agenthub
|
76
|
+
await self.session.authenticate(self.routes)
|
77
|
+
asyncio.create_task(self.session.listen(self.responder))
|
78
|
+
|
79
|
+
self.router = AttpRouter(self.responder, self.session)
|
80
|
+
self.inference = AttpInferenceAPI(self.router)
|
81
|
+
|
82
|
+
self.add_event_handler("tools:call", "message", self._tool_callback)
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
self.disposable = self.responder.pipe(
|
87
|
+
ops.subscribe_on(AsyncIOScheduler(asyncio.get_event_loop())),
|
88
|
+
).subscribe(
|
89
|
+
on_next=lambda item: self.logger.debug(f"Received message on route {item.route_id} with correlation ID {item.correlation_id}"),
|
90
|
+
on_error=lambda e: self.logger.error(f"Error in responder stream: {e}"),
|
91
|
+
)
|
92
|
+
|
93
|
+
async def close(self):
|
94
|
+
if self.session:
|
95
|
+
await self.session.close()
|
96
|
+
self.session = None
|
97
|
+
self.is_connected = False
|
98
|
+
|
99
|
+
@cached_property
|
100
|
+
def tools(self):
|
101
|
+
return ToolsManager(self.router)
|
102
|
+
|
103
|
+
async def catalog(self, catalog_name: str):
|
104
|
+
if any(c.catalog_name == catalog_name for c in self.catalogs):
|
105
|
+
return next(c for c in self.catalogs if c.catalog_name == catalog_name)
|
106
|
+
|
107
|
+
catalog = await self.router.send(
|
108
|
+
"tools:catalogs:specific",
|
109
|
+
Serializable[dict[str, str]]({"catalog_name": catalog_name}),
|
110
|
+
timeout=10,
|
111
|
+
expected_response=ICatalogResponse
|
112
|
+
)
|
113
|
+
self.catalogs.append(
|
114
|
+
AttpCatalog(id=catalog.catalog_id, catalog_name=catalog_name, manager=self.tools)
|
115
|
+
)
|
116
|
+
|
117
|
+
await self.catalogs[-1].start_tool_listener()
|
118
|
+
|
119
|
+
return self.catalogs[-1] # Return the newly added catalog
|
120
|
+
|
121
|
+
async def close_catalog(self, catalog: AttpCatalog):
|
122
|
+
await catalog.detach_all_tools()
|
123
|
+
self.catalogs.remove(catalog)
|
124
|
+
|
125
|
+
async def _tool_callback(self, message: PyAttpMessage):
|
126
|
+
if not self.session:
|
127
|
+
raise DeadSessionError(self.organization_id)
|
128
|
+
|
129
|
+
if not message.correlation_id:
|
130
|
+
await self.session.send_error(IErr(
|
131
|
+
detail={"message": "Correlation ID was missing in the message.", "code": "MissingCorrelationId"},
|
132
|
+
))
|
133
|
+
return
|
134
|
+
|
135
|
+
print("TOOL CALLBACK MESSAGE:", message.payload)
|
136
|
+
try:
|
137
|
+
envelope = envelopizer.envelopize(message)
|
138
|
+
except ValueError as e:
|
139
|
+
await self.session.send_error(IErr(
|
140
|
+
detail={"message": str(e), "code": "InvalidPayload"},
|
141
|
+
))
|
142
|
+
return
|
143
|
+
|
144
|
+
catalog = next((c for c in self.catalogs if c.id == envelope.tool_id), None)
|
145
|
+
if not catalog:
|
146
|
+
await self.session.send_error(IErr(
|
147
|
+
detail={"message": f"Catalog with id {envelope.tool_id} not found.", "code": "NotFoundError"},
|
148
|
+
))
|
149
|
+
return
|
150
|
+
|
151
|
+
response = await catalog.handle_callback(envelope)
|
152
|
+
|
153
|
+
await self.session.respond(route=message.route_id, correlation_id=message.correlation_id, payload=response)
|
154
|
+
|
155
|
+
async def _handle_incoming(self, message: PyAttpMessage):
|
156
|
+
relevant_route = next((route for route in self.routes if route.route_id == message.route_id), None)
|
157
|
+
|
158
|
+
if not relevant_route:
|
159
|
+
if self.logger:
|
160
|
+
self.logger.warning(f"Received message for unknown route ID {message.route_id}. Ignoring.")
|
161
|
+
return
|
162
|
+
|
163
|
+
response = await relevant_route.callback(message)
|
164
|
+
|
165
|
+
if message.command_type == AttpCommand.CALL:
|
166
|
+
if not self.session:
|
167
|
+
raise DeadSessionError(self.organization_id)
|
168
|
+
|
169
|
+
if not message.correlation_id:
|
170
|
+
await self.session.send_error(IErr(
|
171
|
+
detail={"message": "Correlation ID was missing in the message.", "code": "MissingCorrelationId"},
|
172
|
+
))
|
173
|
+
return
|
174
|
+
|
175
|
+
await self.session.respond(
|
176
|
+
route=message.route_id,
|
177
|
+
correlation_id=message.correlation_id,
|
178
|
+
payload=response
|
179
|
+
)
|
180
|
+
|
181
|
+
def add_event_handler(
|
182
|
+
self,
|
183
|
+
pattern: str,
|
184
|
+
route_type: RouteType,
|
185
|
+
callback: Callable[..., Any],
|
186
|
+
):
|
187
|
+
if route_type in ["connect", "disconnect"]:
|
188
|
+
self.routes.append(
|
189
|
+
AttpRouteMapping(
|
190
|
+
pattern=pattern,
|
191
|
+
route_id=0,
|
192
|
+
route_type=route_type,
|
193
|
+
callback=callback
|
194
|
+
)
|
195
|
+
)
|
196
|
+
return
|
197
|
+
|
198
|
+
self.routes.append(
|
199
|
+
AttpRouteMapping(
|
200
|
+
pattern=pattern,
|
201
|
+
route_id=self.route_increment_index,
|
202
|
+
route_type=route_type,
|
203
|
+
callback=callback
|
204
|
+
)
|
205
|
+
)
|
206
|
+
|
207
|
+
self.route_increment_index += 1
|
@@ -18,6 +18,79 @@ class AttpInferenceAPI:
|
|
18
18
|
self.router = router
|
19
19
|
self.logger = logger
|
20
20
|
|
21
|
+
async def create_chat(
|
22
|
+
self,
|
23
|
+
name: str,
|
24
|
+
agent_id: int | None = None,
|
25
|
+
agent_name: str | None = None,
|
26
|
+
mode: str = "agent_autopilot",
|
27
|
+
platform: str = "unknown",
|
28
|
+
responsible: int | None = None,
|
29
|
+
client_id: str | None = None,
|
30
|
+
created_by_id: int | None = None,
|
31
|
+
timeout: float = 30
|
32
|
+
):
|
33
|
+
"""
|
34
|
+
Create chat for inference.
|
35
|
+
TODO: Implement own chat manager for chats, just like I did with catalogs.
|
36
|
+
"""
|
37
|
+
response = await self.router.send(
|
38
|
+
"messages:chat:create",
|
39
|
+
Serializable[dict[str, Any]]({
|
40
|
+
"name": name,
|
41
|
+
"agent_id": agent_id,
|
42
|
+
"agent_name": agent_name,
|
43
|
+
"mode": mode,
|
44
|
+
"platform": platform,
|
45
|
+
"responsible": responsible,
|
46
|
+
"client_id": client_id,
|
47
|
+
"created_by_id": created_by_id
|
48
|
+
}),
|
49
|
+
timeout=timeout,
|
50
|
+
expected_response=dict[str, Any]
|
51
|
+
)
|
52
|
+
|
53
|
+
return response
|
54
|
+
|
55
|
+
async def change_chat_agent(
|
56
|
+
self,
|
57
|
+
chat_id: UUID,
|
58
|
+
agent_id: int | None = None,
|
59
|
+
agent_name: str | None = None,
|
60
|
+
timeout: float = 30
|
61
|
+
) -> dict[str, Any]:
|
62
|
+
"""
|
63
|
+
Change the agent associated with a chat.
|
64
|
+
|
65
|
+
Parameters
|
66
|
+
----------
|
67
|
+
chat_id : UUID
|
68
|
+
The ID of the chat to change the agent for.
|
69
|
+
agent_id : int | None, optional
|
70
|
+
The ID of the new agent to associate with the chat, by default None.
|
71
|
+
agent_name : str | None, optional
|
72
|
+
The name of the new agent to associate with the chat, by default None.
|
73
|
+
timeout : float, optional
|
74
|
+
The timeout for the request, by default 30.
|
75
|
+
|
76
|
+
Returns
|
77
|
+
-------
|
78
|
+
dict[str, Any]
|
79
|
+
The response from the change agent request.
|
80
|
+
"""
|
81
|
+
response = await self.router.send(
|
82
|
+
"messages:chat:change_agent",
|
83
|
+
Serializable[dict[str, Any]]({
|
84
|
+
"chat_id": str(chat_id),
|
85
|
+
"agent_id": agent_id,
|
86
|
+
"agent_name": agent_name
|
87
|
+
}),
|
88
|
+
timeout=timeout,
|
89
|
+
expected_response=dict[str, Any]
|
90
|
+
)
|
91
|
+
|
92
|
+
return response
|
93
|
+
|
21
94
|
async def invoke_inference(
|
22
95
|
self,
|
23
96
|
agent_id: int | None = None,
|
@@ -215,7 +215,7 @@ class SessionDriver:
|
|
215
215
|
)
|
216
216
|
)
|
217
217
|
|
218
|
-
async def respond(self, correlation_id: bytes, payload: FixedBaseModel | Any | None = None):
|
218
|
+
async def respond(self, route: int | str, correlation_id: bytes, payload: FixedBaseModel | Serializable | Any | None = None):
|
219
219
|
"""
|
220
220
|
For responding to `AttpCommand.CALL`. Used only for correlated requests.
|
221
221
|
It sends response (acknowledgement) message signed as `AttpCommand.ACK` to the request.
|
@@ -227,8 +227,16 @@ class SessionDriver:
|
|
227
227
|
payload : FixedBaseModel | Serializable | None, optional
|
228
228
|
Response payload, the data that will be sent, by default None
|
229
229
|
"""
|
230
|
+
relevant_route = route
|
231
|
+
|
232
|
+
if not self.server_routes:
|
233
|
+
raise UnauthenticatedError(f"Cannot send an ATTP message with acknowledgement to unauthenticated (route_mapping={route})")
|
234
|
+
|
235
|
+
if isinstance(route, str):
|
236
|
+
relevant_route = resolve_route_by_id("message", route, self.server_routes).route_id
|
237
|
+
|
230
238
|
frame = PyAttpMessage(
|
231
|
-
route_id=
|
239
|
+
route_id=int(relevant_route),
|
232
240
|
command_type=AttpCommand.ACK,
|
233
241
|
correlation_id=correlation_id,
|
234
242
|
payload=serializer.deserialize(payload),
|
@@ -310,6 +318,7 @@ class SessionDriver:
|
|
310
318
|
if not self.session:
|
311
319
|
raise DeadSessionError(self.organization_id)
|
312
320
|
self.session.add_event_handler(self._on_event)
|
321
|
+
|
313
322
|
await asyncio.gather(
|
314
323
|
self.session.start_handler(),
|
315
324
|
self.session.start_listener()
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from attp_client.interfaces.catalogs.tools.envelope import IEnvelope
|
2
|
+
from attp_core.rs_api import PyAttpMessage
|
3
|
+
|
4
|
+
|
5
|
+
def envelopize(message: PyAttpMessage) -> IEnvelope:
|
6
|
+
if not message.payload:
|
7
|
+
raise ValueError("Message payload is empty, cannot envelopize.")
|
8
|
+
|
9
|
+
return IEnvelope.mps(message.payload)
|
@@ -1,119 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from functools import cached_property
|
3
|
-
from logging import Logger, getLogger
|
4
|
-
from typing import Any, Callable, Literal
|
5
|
-
from attp_core.rs_api import AttpClientSession, Limits
|
6
|
-
from reactivex import Subject
|
7
|
-
from attp_core.rs_api import PyAttpMessage
|
8
|
-
|
9
|
-
from attp_client.catalog import AttpCatalog
|
10
|
-
from attp_client.inference import AttpInferenceAPI
|
11
|
-
from attp_client.interfaces.catalogs.catalog import ICatalogResponse
|
12
|
-
from attp_client.misc.serializable import Serializable
|
13
|
-
from attp_client.router import AttpRouter
|
14
|
-
from attp_client.session import SessionDriver
|
15
|
-
from attp_client.tools import ToolsManager
|
16
|
-
from attp_client.types.route_mapping import AttpRouteMapping, RouteType
|
17
|
-
|
18
|
-
class ATTPClient:
|
19
|
-
|
20
|
-
is_connected: bool
|
21
|
-
client: AttpClientSession
|
22
|
-
session: SessionDriver | None
|
23
|
-
routes: list[AttpRouteMapping]
|
24
|
-
inference: AttpInferenceAPI
|
25
|
-
|
26
|
-
def __init__(
|
27
|
-
self,
|
28
|
-
agt_token: str,
|
29
|
-
organization_id: int,
|
30
|
-
*,
|
31
|
-
connection_url: str | None = None,
|
32
|
-
max_retries: int = 20,
|
33
|
-
limits: Limits | None = None,
|
34
|
-
logger: Logger | None = None
|
35
|
-
):
|
36
|
-
self.__agt_token = agt_token
|
37
|
-
self.organization_id = organization_id
|
38
|
-
self.connection_url = connection_url or "attp://localhost:6563"
|
39
|
-
|
40
|
-
self.client = AttpClientSession(self.connection_url)
|
41
|
-
self.session = None
|
42
|
-
self.max_retries = max_retries
|
43
|
-
self.limits = limits or Limits(max_payload_size=50000)
|
44
|
-
self.logger = logger
|
45
|
-
|
46
|
-
self.route_increment_index = 2
|
47
|
-
|
48
|
-
self.responder = Subject[PyAttpMessage]()
|
49
|
-
self.routes = []
|
50
|
-
|
51
|
-
async def connect(self):
|
52
|
-
# Open the connection
|
53
|
-
client = await self.client.connect(self.max_retries, self.limits)
|
54
|
-
|
55
|
-
if not client.session:
|
56
|
-
raise ConnectionError("Failed to connect to ATTP server after 10 attempts!")
|
57
|
-
|
58
|
-
self.session = SessionDriver(
|
59
|
-
client.session,
|
60
|
-
agt_token=self.__agt_token,
|
61
|
-
organization_id=self.organization_id,
|
62
|
-
# route_mappings=self.routes,
|
63
|
-
logger=self.logger or getLogger("Ascender Framework")
|
64
|
-
)
|
65
|
-
asyncio.create_task(self.session.start_listener())
|
66
|
-
# Send an authentication frame as soon as connection estabilishes with agenthub
|
67
|
-
await self.session.authenticate(self.routes)
|
68
|
-
asyncio.create_task(self.session.listen(self.responder))
|
69
|
-
|
70
|
-
self.router = AttpRouter(self.responder, self.session)
|
71
|
-
self.inference = AttpInferenceAPI(self.router)
|
72
|
-
|
73
|
-
async def close(self):
|
74
|
-
if self.session:
|
75
|
-
await self.session.close()
|
76
|
-
self.session = None
|
77
|
-
self.is_connected = False
|
78
|
-
|
79
|
-
@cached_property
|
80
|
-
def tools(self):
|
81
|
-
return ToolsManager(self.router)
|
82
|
-
|
83
|
-
async def catalog(self, catalog_name: str):
|
84
|
-
catalog = await self.router.send(
|
85
|
-
"tools:catalogs:specific",
|
86
|
-
Serializable[dict[str, str]]({"catalog_name": catalog_name}),
|
87
|
-
timeout=10,
|
88
|
-
expected_response=ICatalogResponse
|
89
|
-
)
|
90
|
-
|
91
|
-
return AttpCatalog(id=catalog.catalog_id, catalog_name=catalog_name, manager=self.tools)
|
92
|
-
|
93
|
-
def add_event_handler(
|
94
|
-
self,
|
95
|
-
pattern: str,
|
96
|
-
route_type: RouteType,
|
97
|
-
callback: Callable[..., Any],
|
98
|
-
):
|
99
|
-
if route_type in ["connect", "disconnect"]:
|
100
|
-
self.routes.append(
|
101
|
-
AttpRouteMapping(
|
102
|
-
pattern=pattern,
|
103
|
-
route_id=0,
|
104
|
-
route_type=route_type,
|
105
|
-
callback=callback
|
106
|
-
)
|
107
|
-
)
|
108
|
-
return
|
109
|
-
|
110
|
-
self.routes.append(
|
111
|
-
AttpRouteMapping(
|
112
|
-
pattern=pattern,
|
113
|
-
route_id=self.route_increment_index,
|
114
|
-
route_type=route_type,
|
115
|
-
callback=callback
|
116
|
-
)
|
117
|
-
)
|
118
|
-
|
119
|
-
self.route_increment_index += 1
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/catalogs/tools/envelope.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{attp_client-0.0.8 → attp_client-0.0.10}/src/attp_client/interfaces/inference/enums/message_type.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|