slim-bindings 0.3.6__cp312-cp312-macosx_11_0_arm64.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.
|
@@ -0,0 +1,930 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: slim-bindings
|
|
3
|
+
Version: 0.3.6
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Intended Audience :: Developers
|
|
6
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Summary: SLIM Rust bindings for Python
|
|
13
|
+
License: Apache-2.0
|
|
14
|
+
Requires-Python: >=3.9, <4.0
|
|
15
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
16
|
+
Project-URL: Repository, https://github.com/agntcy/slim
|
|
17
|
+
Project-URL: Issues, https://github.com/agntcy/slim/issues
|
|
18
|
+
Project-URL: Changelog, https://github.com/agntcy/slim/blob/main/data-plane/python-bindings/CHANGELOG.md
|
|
19
|
+
|
|
20
|
+
# SLIM Python Bindings
|
|
21
|
+
|
|
22
|
+
Bindings to call the SLIM APIs from a python program.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install slim-bindings
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Include as dependency
|
|
31
|
+
|
|
32
|
+
### With pyproject.toml
|
|
33
|
+
|
|
34
|
+
```toml
|
|
35
|
+
[project]
|
|
36
|
+
name = "slim-example"
|
|
37
|
+
version = "0.1.0"
|
|
38
|
+
description = "Python program using SLIM"
|
|
39
|
+
requires-python = ">=3.9"
|
|
40
|
+
dependencies = [
|
|
41
|
+
"slim-bindings>=0.1.0"
|
|
42
|
+
]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### With poetry project
|
|
46
|
+
|
|
47
|
+
```toml
|
|
48
|
+
[tool.poetry]
|
|
49
|
+
name = "slim-example"
|
|
50
|
+
version = "0.1.0"
|
|
51
|
+
description = "Python program using SLIM"
|
|
52
|
+
|
|
53
|
+
[tool.poetry.dependencies]
|
|
54
|
+
python = ">=3.9,<3.14"
|
|
55
|
+
slim-bindings = ">=0.1.0"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Example programs
|
|
59
|
+
|
|
60
|
+
### Server
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Copyright AGNTCY Contributors (https://github.com/agntcy)
|
|
64
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
65
|
+
|
|
66
|
+
import argparse
|
|
67
|
+
import asyncio
|
|
68
|
+
from signal import SIGINT
|
|
69
|
+
|
|
70
|
+
import slim_bindings
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def run_server(address: str, enable_opentelemetry: bool):
|
|
74
|
+
# init tracing
|
|
75
|
+
slim_bindings.init_tracing(
|
|
76
|
+
{
|
|
77
|
+
"log_level": "debug"
|
|
78
|
+
"opentelemetry": {
|
|
79
|
+
"enabled": enable_opentelemetry
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
global slim
|
|
85
|
+
# create new slim object
|
|
86
|
+
slim = await slim_bindings.Slim.new("cisco", "default", "slim")
|
|
87
|
+
|
|
88
|
+
# Run as server
|
|
89
|
+
await slim.run_server({"endpoint": address, "tls": {"insecure": True}})
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
async def main():
|
|
93
|
+
parser = argparse.ArgumentParser(
|
|
94
|
+
description="Command line client for slim server."
|
|
95
|
+
)
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"-s", "--slim", type=str, help="SLIM address.", default="127.0.0.1:12345"
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--enable-opentelemetry",
|
|
101
|
+
"-t",
|
|
102
|
+
action="store_true",
|
|
103
|
+
default=False,
|
|
104
|
+
help="Enable OpenTelemetry tracing.",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
args = parser.parse_args()
|
|
108
|
+
|
|
109
|
+
# Create an asyncio event to keep the loop running until interrupted
|
|
110
|
+
stop_event = asyncio.Event()
|
|
111
|
+
|
|
112
|
+
# Define a shutdown handler to set the event when interrupted
|
|
113
|
+
def shutdown():
|
|
114
|
+
print("\nShutting down...")
|
|
115
|
+
stop_event.set()
|
|
116
|
+
|
|
117
|
+
# Register the shutdown handler for SIGINT
|
|
118
|
+
loop = asyncio.get_running_loop()
|
|
119
|
+
loop.add_signal_handler(SIGINT, shutdown)
|
|
120
|
+
|
|
121
|
+
# Run the client task
|
|
122
|
+
client_task = asyncio.create_task(
|
|
123
|
+
run_server(args.slim, args.enable_opentelemetry)
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Wait until the stop event is set
|
|
127
|
+
await stop_event.wait()
|
|
128
|
+
|
|
129
|
+
# Cancel the client task
|
|
130
|
+
client_task.cancel()
|
|
131
|
+
try:
|
|
132
|
+
await client_task
|
|
133
|
+
except asyncio.CancelledError:
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
try:
|
|
139
|
+
asyncio.run(main())
|
|
140
|
+
except KeyboardInterrupt:
|
|
141
|
+
print("Program terminated by user.")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### PubSub Client
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# Copyright AGNTCY Contributors (https://github.com/agntcy)
|
|
148
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
149
|
+
|
|
150
|
+
import argparse
|
|
151
|
+
import asyncio
|
|
152
|
+
import datetime
|
|
153
|
+
|
|
154
|
+
import slim_bindings
|
|
155
|
+
|
|
156
|
+
class color:
|
|
157
|
+
PURPLE = "\033[95m"
|
|
158
|
+
CYAN = "\033[96m"
|
|
159
|
+
DARKCYAN = "\033[36m"
|
|
160
|
+
BLUE = "\033[94m"
|
|
161
|
+
GREEN = "\033[92m"
|
|
162
|
+
YELLOW = "\033[93m"
|
|
163
|
+
RED = "\033[91m"
|
|
164
|
+
BOLD = "\033[1m"
|
|
165
|
+
UNDERLINE = "\033[4m"
|
|
166
|
+
END = "\033[0m"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def format_message(message1, message2):
|
|
170
|
+
return f"{color.BOLD}{color.CYAN}{message1.capitalize() :<45}{color.END}{message2}"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def split_id(id):
|
|
174
|
+
# Split the IDs into their respective components
|
|
175
|
+
try:
|
|
176
|
+
local_organization, local_namespace, local_agent = id.split("/")
|
|
177
|
+
except ValueError as e:
|
|
178
|
+
print("Error: IDs must be in the format organization/namespace/agent.")
|
|
179
|
+
raise e
|
|
180
|
+
|
|
181
|
+
return local_organization, local_namespace, local_agent
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
async def run_client(local_id, remote_id, address, enable_opentelemetry: bool):
|
|
185
|
+
# init tracing
|
|
186
|
+
slim_bindings.init_tracing(
|
|
187
|
+
{
|
|
188
|
+
"log_level": "info"
|
|
189
|
+
"opentelemetry": {
|
|
190
|
+
"enabled": enable_opentelemetry
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Split the local IDs into their respective components
|
|
196
|
+
local_organization, local_namespace, local_agent = split_id(local_id)
|
|
197
|
+
|
|
198
|
+
# Split the remote IDs into their respective components
|
|
199
|
+
remote_organization, remote_namespace, broadcast_topic = split_id(remote_id)
|
|
200
|
+
|
|
201
|
+
name = f"{local_agent}"
|
|
202
|
+
|
|
203
|
+
print(f"Creating participant {name}...")
|
|
204
|
+
|
|
205
|
+
participant = await slim_bindings.Slim.new(
|
|
206
|
+
local_organization, local_namespace, local_agent
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# Connect to slim server
|
|
210
|
+
_ = await participant.connect(
|
|
211
|
+
{"endpoint": address, "tls": {"insecure": True}}
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# set route for the chat, so that messages can be sent to the other participants
|
|
215
|
+
await participant.set_route(remote_organization, remote_namespace, broadcast_topic)
|
|
216
|
+
|
|
217
|
+
# Subscribe to the producer topic
|
|
218
|
+
await participant.subscribe(remote_organization, remote_namespace, broadcast_topic)
|
|
219
|
+
|
|
220
|
+
print(f"{name} -> Creating new pubsub sessions...")
|
|
221
|
+
# create pubsubb session. A pubsub session is a just a bidirectional
|
|
222
|
+
# streaming session, where participants are both sender and receivers
|
|
223
|
+
session_info = await participant.create_session(
|
|
224
|
+
slim_bindings.PySessionConfiguration.Streaming(
|
|
225
|
+
slim_bindings.PySessionDirection.BIDIRECTIONAL,
|
|
226
|
+
topic=slim_bindings.PyAgentType(
|
|
227
|
+
remote_organization, remote_namespace, broadcast_topic
|
|
228
|
+
),
|
|
229
|
+
max_retries=5,
|
|
230
|
+
timeout=datetime.timedelta(seconds=5),
|
|
231
|
+
)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# define the background task
|
|
235
|
+
async def background_task():
|
|
236
|
+
msg = f"Hello from {local_agent}"
|
|
237
|
+
|
|
238
|
+
async with participant:
|
|
239
|
+
while True:
|
|
240
|
+
try:
|
|
241
|
+
# receive message from session
|
|
242
|
+
recv_session, msg_rcv = await participant.receive(
|
|
243
|
+
session=session_info.id
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# Check if the message is calling this specific participant
|
|
247
|
+
# if not, ignore it
|
|
248
|
+
if local_agent in msg_rcv.decode():
|
|
249
|
+
# print the message
|
|
250
|
+
print(f"{name} -> Received message for me: {msg_rcv.decode()}")
|
|
251
|
+
|
|
252
|
+
# send the message to the next participant
|
|
253
|
+
await participant.publish(
|
|
254
|
+
recv_session,
|
|
255
|
+
msg.encode(),
|
|
256
|
+
remote_organization,
|
|
257
|
+
remote_namespace,
|
|
258
|
+
broadcast_topic,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
print(f"{name} -> Sending message to all participants: {msg}")
|
|
262
|
+
else:
|
|
263
|
+
print(
|
|
264
|
+
f"{name} -> Receiving message: {msg_rcv.decode()} - not for me."
|
|
265
|
+
)
|
|
266
|
+
except asyncio.CancelledError:
|
|
267
|
+
break
|
|
268
|
+
except Exception as e:
|
|
269
|
+
print(f"{name} -> Error receiving message: {e}")
|
|
270
|
+
break
|
|
271
|
+
|
|
272
|
+
receive_task = asyncio.create_task(background_task())
|
|
273
|
+
|
|
274
|
+
async def background_task_keyboard():
|
|
275
|
+
while True:
|
|
276
|
+
user_input = await asyncio.to_thread(input, "message> ")
|
|
277
|
+
if user_input == "exit":
|
|
278
|
+
break
|
|
279
|
+
|
|
280
|
+
# Send the message to the all participants
|
|
281
|
+
await participant.publish(
|
|
282
|
+
session_info,
|
|
283
|
+
f"{user_input}".encode(),
|
|
284
|
+
remote_organization,
|
|
285
|
+
remote_namespace,
|
|
286
|
+
broadcast_topic,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
receive_task.cancel()
|
|
290
|
+
|
|
291
|
+
send_task = asyncio.create_task(background_task_keyboard())
|
|
292
|
+
|
|
293
|
+
# Wait for both tasks to finish
|
|
294
|
+
await asyncio.gather(receive_task, send_task)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
async def main():
|
|
298
|
+
parser = argparse.ArgumentParser(
|
|
299
|
+
description="Command line client for message passing."
|
|
300
|
+
)
|
|
301
|
+
parser.add_argument(
|
|
302
|
+
"-l",
|
|
303
|
+
"--local",
|
|
304
|
+
type=str,
|
|
305
|
+
help="Local ID in the format organization/namespace/agent.",
|
|
306
|
+
)
|
|
307
|
+
parser.add_argument(
|
|
308
|
+
"-r",
|
|
309
|
+
"--remote",
|
|
310
|
+
type=str,
|
|
311
|
+
help="Remote ID in the format organization/namespace/agent.",
|
|
312
|
+
)
|
|
313
|
+
parser.add_argument(
|
|
314
|
+
"-s",
|
|
315
|
+
"--slim",
|
|
316
|
+
type=str,
|
|
317
|
+
help="Slim address.",
|
|
318
|
+
default="http://127.0.0.1:46357",
|
|
319
|
+
)
|
|
320
|
+
parser.add_argument(
|
|
321
|
+
"-t",
|
|
322
|
+
"--enable-opentelemetry",
|
|
323
|
+
action="store_true",
|
|
324
|
+
default=False,
|
|
325
|
+
help="Enable OpenTelemetry tracing.",
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
args = parser.parse_args()
|
|
329
|
+
|
|
330
|
+
# Run the client with the specified local ID, remote ID, and optional message
|
|
331
|
+
await run_client(
|
|
332
|
+
args.local,
|
|
333
|
+
args.remote,
|
|
334
|
+
args.slim,
|
|
335
|
+
args.enable_opentelemetry,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
if __name__ == "__main__":
|
|
340
|
+
try:
|
|
341
|
+
asyncio.run(main())
|
|
342
|
+
except KeyboardInterrupt:
|
|
343
|
+
print("Program terminated by user.")
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Streaming producer and consumer
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
# Copyright AGNTCY Contributors (https://github.com/agntcy)
|
|
350
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
351
|
+
|
|
352
|
+
import argparse
|
|
353
|
+
import asyncio
|
|
354
|
+
import datetime
|
|
355
|
+
import os
|
|
356
|
+
|
|
357
|
+
import slim_bindings
|
|
358
|
+
|
|
359
|
+
class color:
|
|
360
|
+
PURPLE = "\033[95m"
|
|
361
|
+
CYAN = "\033[96m"
|
|
362
|
+
DARKCYAN = "\033[36m"
|
|
363
|
+
BLUE = "\033[94m"
|
|
364
|
+
GREEN = "\033[92m"
|
|
365
|
+
YELLOW = "\033[93m"
|
|
366
|
+
RED = "\033[91m"
|
|
367
|
+
BOLD = "\033[1m"
|
|
368
|
+
UNDERLINE = "\033[4m"
|
|
369
|
+
END = "\033[0m"
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def format_message(message1, message2):
|
|
373
|
+
return f"{color.BOLD}{color.CYAN}{message1.capitalize() :<45}{color.END}{message2}"
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def split_id(id):
|
|
377
|
+
# Split the IDs into their respective components
|
|
378
|
+
try:
|
|
379
|
+
local_organization, local_namespace, local_agent = id.split("/")
|
|
380
|
+
except ValueError as e:
|
|
381
|
+
print("Error: IDs must be in the format organization/namespace/agent.")
|
|
382
|
+
raise e
|
|
383
|
+
|
|
384
|
+
return local_organization, local_namespace, local_agent
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
async def run_client(
|
|
388
|
+
local_id, remote_id, address, producer, enable_opentelemetry: bool
|
|
389
|
+
):
|
|
390
|
+
# init tracing
|
|
391
|
+
slim_bindings.init_tracing(
|
|
392
|
+
{
|
|
393
|
+
"log_level": "info"
|
|
394
|
+
"opentelemetry": {
|
|
395
|
+
"enabled": enable_opentelemetry
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
# Split the IDs into their respective components
|
|
401
|
+
local_organization, local_namespace, local_agent = split_id(local_id)
|
|
402
|
+
|
|
403
|
+
# create new slim object
|
|
404
|
+
slim = await slim_bindings.Slim.new(
|
|
405
|
+
local_organization, local_namespace, local_agent
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
# Connect to the service and subscribe for the local name
|
|
409
|
+
print(format_message("connecting to:", address))
|
|
410
|
+
_ = await slim.connect({"endpoint": address, "tls": {"insecure": True}})
|
|
411
|
+
|
|
412
|
+
# Split the IDs into their respective components
|
|
413
|
+
remote_organization, remote_namespace, broadcast_topic = split_id(remote_id)
|
|
414
|
+
|
|
415
|
+
# Get the local agent instance from env
|
|
416
|
+
instance = os.getenv("SLIM_INSTANCE_ID", local_agent)
|
|
417
|
+
|
|
418
|
+
async with slim:
|
|
419
|
+
if producer:
|
|
420
|
+
# Create a route to the remote ID
|
|
421
|
+
await slim.set_route(
|
|
422
|
+
remote_organization, remote_namespace, broadcast_topic
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
# create streaming session with default config
|
|
426
|
+
session_info = await slim.create_session(
|
|
427
|
+
slim_bindings.PySessionConfiguration.Streaming(
|
|
428
|
+
slim_bindings.PySessionDirection.SENDER,
|
|
429
|
+
topic=None,
|
|
430
|
+
max_retries=5,
|
|
431
|
+
timeout=datetime.timedelta(seconds=5),
|
|
432
|
+
)
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
# initialize count
|
|
436
|
+
count = 0
|
|
437
|
+
|
|
438
|
+
while True:
|
|
439
|
+
try:
|
|
440
|
+
# Send a message
|
|
441
|
+
print(
|
|
442
|
+
format_message(
|
|
443
|
+
f"{instance} streaming message to {remote_organization}/{remote_namespace}/{broadcast_topic}: ",
|
|
444
|
+
f"{count}",
|
|
445
|
+
)
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
# Send the message and wait for a reply
|
|
449
|
+
await slim.publish(
|
|
450
|
+
session_info,
|
|
451
|
+
f"{count}".encode(),
|
|
452
|
+
remote_organization,
|
|
453
|
+
remote_namespace,
|
|
454
|
+
broadcast_topic,
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
count += 1
|
|
458
|
+
except Exception as e:
|
|
459
|
+
print("received error: ", e)
|
|
460
|
+
finally:
|
|
461
|
+
await asyncio.sleep(1)
|
|
462
|
+
else:
|
|
463
|
+
# subscribe to streaming session
|
|
464
|
+
await slim.subscribe(
|
|
465
|
+
remote_organization, remote_namespace, broadcast_topic
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
# Wait for messages and not reply
|
|
469
|
+
while True:
|
|
470
|
+
session_info, _ = await slim.receive()
|
|
471
|
+
print(
|
|
472
|
+
format_message(
|
|
473
|
+
f"{instance.capitalize()} received a new session:",
|
|
474
|
+
f"{session_info.id}",
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
async def background_task(session_info):
|
|
479
|
+
while True:
|
|
480
|
+
# Receive the message from the session
|
|
481
|
+
session, msg = await slim.receive(session=session_info)
|
|
482
|
+
print(
|
|
483
|
+
format_message(
|
|
484
|
+
f"{local_agent.capitalize()} received from {remote_organization}/{remote_namespace}/{broadcast_topic}: ",
|
|
485
|
+
f"{msg.decode()}",
|
|
486
|
+
)
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
asyncio.create_task(background_task(session_info.id))
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
async def main():
|
|
493
|
+
parser = argparse.ArgumentParser(
|
|
494
|
+
description="Command line client for message passing."
|
|
495
|
+
)
|
|
496
|
+
parser.add_argument(
|
|
497
|
+
"-l",
|
|
498
|
+
"--local",
|
|
499
|
+
type=str,
|
|
500
|
+
help="Local ID in the format organization/namespace/agent.",
|
|
501
|
+
)
|
|
502
|
+
parser.add_argument(
|
|
503
|
+
"-r",
|
|
504
|
+
"--remote",
|
|
505
|
+
type=str,
|
|
506
|
+
help="Remote ID in the format organization/namespace/agent.",
|
|
507
|
+
)
|
|
508
|
+
parser.add_argument(
|
|
509
|
+
"-s",
|
|
510
|
+
"--slim",
|
|
511
|
+
type=str,
|
|
512
|
+
help="SLIM address.",
|
|
513
|
+
default="http://127.0.0.1:46357",
|
|
514
|
+
)
|
|
515
|
+
parser.add_argument(
|
|
516
|
+
"-t",
|
|
517
|
+
"--enable-opentelemetry",
|
|
518
|
+
action="store_true",
|
|
519
|
+
default=False,
|
|
520
|
+
help="Enable OpenTelemetry tracing.",
|
|
521
|
+
)
|
|
522
|
+
parser.add_argument(
|
|
523
|
+
"-p",
|
|
524
|
+
"--producer",
|
|
525
|
+
action="store_true",
|
|
526
|
+
default=False,
|
|
527
|
+
help="Enable producer mode.",
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
args = parser.parse_args()
|
|
531
|
+
|
|
532
|
+
# Run the client with the specified local ID, remote ID, and optional message
|
|
533
|
+
await run_client(
|
|
534
|
+
args.local,
|
|
535
|
+
args.remote,
|
|
536
|
+
args.slim,
|
|
537
|
+
args.producer,
|
|
538
|
+
args.enable_opentelemetry,
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
if __name__ == "__main__":
|
|
543
|
+
try:
|
|
544
|
+
asyncio.run(main())
|
|
545
|
+
except KeyboardInterrupt:
|
|
546
|
+
print("Program terminated by user.")
|
|
547
|
+
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Fire And Forget sender and receiver
|
|
551
|
+
|
|
552
|
+
```python
|
|
553
|
+
# Copyright AGNTCY Contributors (https://github.com/agntcy)
|
|
554
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
555
|
+
|
|
556
|
+
import argparse
|
|
557
|
+
import asyncio
|
|
558
|
+
import os
|
|
559
|
+
|
|
560
|
+
import slim_bindings
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
class color:
|
|
564
|
+
PURPLE = "\033[95m"
|
|
565
|
+
CYAN = "\033[96m"
|
|
566
|
+
DARKCYAN = "\033[36m"
|
|
567
|
+
BLUE = "\033[94m"
|
|
568
|
+
GREEN = "\033[92m"
|
|
569
|
+
YELLOW = "\033[93m"
|
|
570
|
+
RED = "\033[91m"
|
|
571
|
+
BOLD = "\033[1m"
|
|
572
|
+
UNDERLINE = "\033[4m"
|
|
573
|
+
END = "\033[0m"
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
def format_message(message1, message2):
|
|
577
|
+
return f"{color.BOLD}{color.CYAN}{message1.capitalize() :<45}{color.END}{message2}"
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def split_id(id):
|
|
581
|
+
# Split the IDs into their respective components
|
|
582
|
+
try:
|
|
583
|
+
local_organization, local_namespace, local_agent = id.split("/")
|
|
584
|
+
except ValueError as e:
|
|
585
|
+
print("Error: IDs must be in the format organization/namespace/agent.")
|
|
586
|
+
raise e
|
|
587
|
+
|
|
588
|
+
return local_organization, local_namespace, local_agent
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
async def run_client(
|
|
592
|
+
local_id: str,
|
|
593
|
+
remote_id: str,
|
|
594
|
+
message: str,
|
|
595
|
+
address: str,
|
|
596
|
+
iterations: int,
|
|
597
|
+
enable_opentelemetry: bool,
|
|
598
|
+
):
|
|
599
|
+
# init tracing
|
|
600
|
+
slim_bindings.init_tracing(
|
|
601
|
+
{
|
|
602
|
+
"log_level": "info"
|
|
603
|
+
"opentelemetry": {
|
|
604
|
+
"enabled": enable_opentelemetry
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
local_organization, local_namespace, local_agent = split_id(local_id)
|
|
610
|
+
|
|
611
|
+
# create new slim object
|
|
612
|
+
slim = await slim_bindings.Slim.new(
|
|
613
|
+
local_organization, local_namespace, local_agent
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
# Connect to remote slim server
|
|
617
|
+
print(format_message(f"connecting to: {address}"))
|
|
618
|
+
_ = await slim.connect({"endpoint": address, "tls": {"insecure": True}})
|
|
619
|
+
|
|
620
|
+
# Get the local agent instance from env
|
|
621
|
+
instance = os.getenv("SLIM_INSTANCE_ID", local_agent)
|
|
622
|
+
|
|
623
|
+
async with slim:
|
|
624
|
+
if message:
|
|
625
|
+
# Split the IDs into their respective components
|
|
626
|
+
remote_organization, remote_namespace, remote_agent = split_id(remote_id)
|
|
627
|
+
|
|
628
|
+
# Create a route to the remote ID
|
|
629
|
+
await slim.set_route(remote_organization, remote_namespace, remote_agent)
|
|
630
|
+
|
|
631
|
+
# create a session
|
|
632
|
+
session = await slim.create_session(
|
|
633
|
+
slim_bindings.PySessionConfiguration.FireAndForget()
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
for i in range(0, iterations):
|
|
637
|
+
try:
|
|
638
|
+
# Send the message
|
|
639
|
+
await slim.publish(
|
|
640
|
+
session,
|
|
641
|
+
message.encode(),
|
|
642
|
+
remote_organization,
|
|
643
|
+
remote_namespace,
|
|
644
|
+
remote_agent,
|
|
645
|
+
)
|
|
646
|
+
print(format_message(f"{instance} sent:", message))
|
|
647
|
+
|
|
648
|
+
# Wait for a reply
|
|
649
|
+
session_info, msg = await slim.receive(session=session.id)
|
|
650
|
+
print(
|
|
651
|
+
format_message(
|
|
652
|
+
f"{instance.capitalize()} received (from session {session_info.id}):",
|
|
653
|
+
f"{msg.decode()}",
|
|
654
|
+
)
|
|
655
|
+
)
|
|
656
|
+
except Exception as e:
|
|
657
|
+
print("received error: ", e)
|
|
658
|
+
|
|
659
|
+
await asyncio.sleep(1)
|
|
660
|
+
else:
|
|
661
|
+
# Wait for a message and reply in a loop
|
|
662
|
+
while True:
|
|
663
|
+
session_info, _ = await slim.receive()
|
|
664
|
+
print(
|
|
665
|
+
format_message(
|
|
666
|
+
f"{instance.capitalize()} received a new session:",
|
|
667
|
+
f"{session_info.id}",
|
|
668
|
+
)
|
|
669
|
+
)
|
|
670
|
+
|
|
671
|
+
async def background_task(session_id):
|
|
672
|
+
while True:
|
|
673
|
+
# Receive the message from the session
|
|
674
|
+
session, msg = await slim.receive(session=session_id)
|
|
675
|
+
print(
|
|
676
|
+
format_message(
|
|
677
|
+
f"{instance.capitalize()} received (from session {session_id}):",
|
|
678
|
+
f"{msg.decode()}",
|
|
679
|
+
)
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
ret = f"{msg.decode()} from {instance}"
|
|
683
|
+
|
|
684
|
+
await slim.publish_to(session, ret.encode())
|
|
685
|
+
print(format_message(f"{instance.capitalize()} replies:", ret))
|
|
686
|
+
|
|
687
|
+
asyncio.create_task(background_task(session_info.id))
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
async def main():
|
|
691
|
+
parser = argparse.ArgumentParser(
|
|
692
|
+
description="Command line client for message passing."
|
|
693
|
+
)
|
|
694
|
+
parser.add_argument(
|
|
695
|
+
"-l",
|
|
696
|
+
"--local",
|
|
697
|
+
type=str,
|
|
698
|
+
help="Local ID in the format organization/namespace/agent.",
|
|
699
|
+
)
|
|
700
|
+
parser.add_argument(
|
|
701
|
+
"-r",
|
|
702
|
+
"--remote",
|
|
703
|
+
type=str,
|
|
704
|
+
help="Remote ID in the format organization/namespace/agent.",
|
|
705
|
+
)
|
|
706
|
+
parser.add_argument("-m", "--message", type=str, help="Message to send.")
|
|
707
|
+
parser.add_argument(
|
|
708
|
+
"-s",
|
|
709
|
+
"--slim",
|
|
710
|
+
type=str,
|
|
711
|
+
help="SLIM address.",
|
|
712
|
+
default="http://127.0.0.1:46357",
|
|
713
|
+
)
|
|
714
|
+
parser.add_argument(
|
|
715
|
+
"-i",
|
|
716
|
+
"--iterations",
|
|
717
|
+
type=int,
|
|
718
|
+
help="Number of messages to send, one per second.",
|
|
719
|
+
)
|
|
720
|
+
parser.add_argument(
|
|
721
|
+
"-t",
|
|
722
|
+
"--enable-opentelemetry",
|
|
723
|
+
action="store_true",
|
|
724
|
+
default=False,
|
|
725
|
+
help="Enable OpenTelemetry tracing.",
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
args = parser.parse_args()
|
|
729
|
+
|
|
730
|
+
# Run the client with the specified local ID, remote ID, and optional message
|
|
731
|
+
await run_client(
|
|
732
|
+
args.local,
|
|
733
|
+
args.remote,
|
|
734
|
+
args.message,
|
|
735
|
+
args.slim,
|
|
736
|
+
args.iterations,
|
|
737
|
+
args.enable_opentelemetry,
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
if __name__ == "__main__":
|
|
742
|
+
try:
|
|
743
|
+
asyncio.run(main())
|
|
744
|
+
except KeyboardInterrupt:
|
|
745
|
+
print("Program terminated by user.")
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
### Request/Response Requester and Responder
|
|
749
|
+
|
|
750
|
+
```python
|
|
751
|
+
# Copyright AGNTCY Contributors (https://github.com/agntcy)
|
|
752
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
753
|
+
|
|
754
|
+
import argparse
|
|
755
|
+
import asyncio
|
|
756
|
+
import os
|
|
757
|
+
|
|
758
|
+
import slim_bindings
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
class color:
|
|
762
|
+
PURPLE = "\033[95m"
|
|
763
|
+
CYAN = "\033[96m"
|
|
764
|
+
DARKCYAN = "\033[36m"
|
|
765
|
+
BLUE = "\033[94m"
|
|
766
|
+
GREEN = "\033[92m"
|
|
767
|
+
YELLOW = "\033[93m"
|
|
768
|
+
RED = "\033[91m"
|
|
769
|
+
BOLD = "\033[1m"
|
|
770
|
+
UNDERLINE = "\033[4m"
|
|
771
|
+
END = "\033[0m"
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
def format_message(message1, message2):
|
|
775
|
+
return f"{color.BOLD}{color.CYAN}{message1.capitalize() :<45}{color.END}{message2}"
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
def split_id(id):
|
|
779
|
+
# Split the IDs into their respective components
|
|
780
|
+
try:
|
|
781
|
+
local_organization, local_namespace, local_agent = id.split("/")
|
|
782
|
+
except ValueError as e:
|
|
783
|
+
print("Error: IDs must be in the format organization/namespace/agent.")
|
|
784
|
+
raise e
|
|
785
|
+
|
|
786
|
+
return local_organization, local_namespace, local_agent
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
async def run_client(local_id, remote_id, message, address, enable_opentelemetry: bool):
|
|
790
|
+
# init tracing
|
|
791
|
+
slim_bindings.init_tracing(
|
|
792
|
+
{
|
|
793
|
+
"log_level": "info"
|
|
794
|
+
"opentelemetry": {
|
|
795
|
+
"enabled": enable_opentelemetry
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
# Split the IDs into their respective components
|
|
801
|
+
local_organization, local_namespace, local_agent = split_id(local_id)
|
|
802
|
+
|
|
803
|
+
# create new slim object
|
|
804
|
+
slim = await slim_bindings.Slim.new(
|
|
805
|
+
local_organization, local_namespace, local_agent
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
# Connect to the service and subscribe for the local name
|
|
809
|
+
print(format_message("connecting to:", address))
|
|
810
|
+
_ = await slim.connect({"endpoint": address, "tls": {"insecure": True}})
|
|
811
|
+
|
|
812
|
+
# Get the local agent instance from env
|
|
813
|
+
instance = os.getenv("SLIM_INSTANCE_ID", local_agent)
|
|
814
|
+
|
|
815
|
+
async with slim:
|
|
816
|
+
if message:
|
|
817
|
+
# Split the IDs into their respective components
|
|
818
|
+
remote_organization, remote_namespace, remote_agent = split_id(remote_id)
|
|
819
|
+
|
|
820
|
+
# Create a route to the remote ID
|
|
821
|
+
await slim.set_route(remote_organization, remote_namespace, remote_agent)
|
|
822
|
+
|
|
823
|
+
# create a session
|
|
824
|
+
session = await slim.create_session(
|
|
825
|
+
slim_bindings.PySessionConfiguration.RequestResponse()
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
try:
|
|
829
|
+
# Send the message and wait for a reply
|
|
830
|
+
session_info, reply = await slim.request_reply(
|
|
831
|
+
session,
|
|
832
|
+
message.encode(),
|
|
833
|
+
remote_organization,
|
|
834
|
+
remote_namespace,
|
|
835
|
+
remote_agent,
|
|
836
|
+
)
|
|
837
|
+
print(format_message(f"{instance} sent:", message))
|
|
838
|
+
|
|
839
|
+
# Print reply and exit
|
|
840
|
+
print(
|
|
841
|
+
format_message(
|
|
842
|
+
f"{instance} received (from session {session_info.id}):",
|
|
843
|
+
f"{reply.decode()}",
|
|
844
|
+
)
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
except Exception as e:
|
|
848
|
+
print("received error: ", e)
|
|
849
|
+
else:
|
|
850
|
+
# Wait for a message and reply in a loop
|
|
851
|
+
while True:
|
|
852
|
+
session_info, _ = await slim.receive()
|
|
853
|
+
print(
|
|
854
|
+
format_message(
|
|
855
|
+
f"{instance.capitalize()} received a new session:",
|
|
856
|
+
f"{session_info.id}",
|
|
857
|
+
)
|
|
858
|
+
)
|
|
859
|
+
|
|
860
|
+
async def background_task(session_id):
|
|
861
|
+
while True:
|
|
862
|
+
# Receive the message from the session
|
|
863
|
+
session, msg = await slim.receive(session=session_id)
|
|
864
|
+
print(
|
|
865
|
+
format_message(
|
|
866
|
+
f"{instance.capitalize()} received (from session {session_id}):",
|
|
867
|
+
f"{msg.decode()}",
|
|
868
|
+
)
|
|
869
|
+
)
|
|
870
|
+
|
|
871
|
+
ret = f"{msg.decode()} from {instance}"
|
|
872
|
+
|
|
873
|
+
await slim.publish_to(session, ret.encode())
|
|
874
|
+
print(format_message(f"{instance.capitalize()} replies:", ret))
|
|
875
|
+
|
|
876
|
+
asyncio.create_task(background_task(session_info.id))
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
async def main():
|
|
880
|
+
parser = argparse.ArgumentParser(
|
|
881
|
+
description="Command line client for message passing."
|
|
882
|
+
)
|
|
883
|
+
parser.add_argument(
|
|
884
|
+
"-l",
|
|
885
|
+
"--local",
|
|
886
|
+
type=str,
|
|
887
|
+
help="Local ID in the format organization/namespace/agent.",
|
|
888
|
+
)
|
|
889
|
+
parser.add_argument(
|
|
890
|
+
"-r",
|
|
891
|
+
"--remote",
|
|
892
|
+
type=str,
|
|
893
|
+
help="Remote ID in the format organization/namespace/agent.",
|
|
894
|
+
)
|
|
895
|
+
parser.add_argument("-m", "--message", type=str, help="Message to send.")
|
|
896
|
+
parser.add_argument(
|
|
897
|
+
"-s",
|
|
898
|
+
"--slim",
|
|
899
|
+
type=str,
|
|
900
|
+
help="SLIM address.",
|
|
901
|
+
default="http://127.0.0.1:46357",
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
parser.add_argument(
|
|
905
|
+
"-t",
|
|
906
|
+
"--enable-opentelemetry",
|
|
907
|
+
action="store_true",
|
|
908
|
+
default=False,
|
|
909
|
+
help="Enable OpenTelemetry tracing.",
|
|
910
|
+
)
|
|
911
|
+
|
|
912
|
+
args = parser.parse_args()
|
|
913
|
+
|
|
914
|
+
# Run the client with the specified local ID, remote ID, and optional message
|
|
915
|
+
await run_client(
|
|
916
|
+
args.local,
|
|
917
|
+
args.remote,
|
|
918
|
+
args.message,
|
|
919
|
+
args.slim,
|
|
920
|
+
args.enable_opentelemetry,
|
|
921
|
+
)
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
if __name__ == "__main__":
|
|
925
|
+
try:
|
|
926
|
+
asyncio.run(main())
|
|
927
|
+
except KeyboardInterrupt:
|
|
928
|
+
print("Program terminated by user.")
|
|
929
|
+
```
|
|
930
|
+
|