bspl 1.0.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.
- bspl-1.0.0/LICENSE +21 -0
- bspl-1.0.0/MANIFEST.in +5 -0
- bspl-1.0.0/PKG-INFO +372 -0
- bspl-1.0.0/README.org +328 -0
- bspl-1.0.0/pyproject.toml +6 -0
- bspl-1.0.0/setup.cfg +75 -0
- bspl-1.0.0/setup.py +25 -0
- bspl-1.0.0/src/bspl/__init__.py +2 -0
- bspl-1.0.0/src/bspl/adapter/__init__.py +3 -0
- bspl-1.0.0/src/bspl/adapter/core.py +624 -0
- bspl-1.0.0/src/bspl/adapter/emitter.py +253 -0
- bspl-1.0.0/src/bspl/adapter/event.py +28 -0
- bspl-1.0.0/src/bspl/adapter/jason.py +190 -0
- bspl-1.0.0/src/bspl/adapter/message.py +248 -0
- bspl-1.0.0/src/bspl/adapter/policies.py +264 -0
- bspl-1.0.0/src/bspl/adapter/policy.gr +32 -0
- bspl-1.0.0/src/bspl/adapter/receiver.py +134 -0
- bspl-1.0.0/src/bspl/adapter/scheduler.py +94 -0
- bspl-1.0.0/src/bspl/adapter/schema.py +41 -0
- bspl-1.0.0/src/bspl/adapter/statistics.py +79 -0
- bspl-1.0.0/src/bspl/adapter/store.py +316 -0
- bspl-1.0.0/src/bspl/generators/__init__.py +12 -0
- bspl-1.0.0/src/bspl/generators/asl.py +273 -0
- bspl-1.0.0/src/bspl/generators/mambo.py +75 -0
- bspl-1.0.0/src/bspl/generators/node_red.py +268 -0
- bspl-1.0.0/src/bspl/langshaw.py +664 -0
- bspl-1.0.0/src/bspl/main.py +132 -0
- bspl-1.0.0/src/bspl/parsers/bspl/__init__.py +128 -0
- bspl-1.0.0/src/bspl/parsers/bspl/bspl.gr +32 -0
- bspl-1.0.0/src/bspl/parsers/bspl/bspl_parser.py +322 -0
- bspl-1.0.0/src/bspl/parsers/bspl/build.py +24 -0
- bspl-1.0.0/src/bspl/parsers/langshaw/__init__.py +39 -0
- bspl-1.0.0/src/bspl/parsers/langshaw/build.py +24 -0
- bspl-1.0.0/src/bspl/parsers/langshaw/langshaw.gr +46 -0
- bspl-1.0.0/src/bspl/parsers/precedence/__init__.py +18 -0
- bspl-1.0.0/src/bspl/parsers/precedence/precedence.gr +33 -0
- bspl-1.0.0/src/bspl/protocol.py +733 -0
- bspl-1.0.0/src/bspl/utils.py +45 -0
- bspl-1.0.0/src/bspl/validation.py +107 -0
- bspl-1.0.0/src/bspl/verification/__init__.py +195 -0
- bspl-1.0.0/src/bspl/verification/logic.py +98 -0
- bspl-1.0.0/src/bspl/verification/lpaths.py +569 -0
- bspl-1.0.0/src/bspl/verification/mambo.py +415 -0
- bspl-1.0.0/src/bspl/verification/paths.py +882 -0
- bspl-1.0.0/src/bspl/verification/precedence.py +411 -0
- bspl-1.0.0/src/bspl/verification/refinement.py +153 -0
- bspl-1.0.0/src/bspl/verification/sat.py +485 -0
- bspl-1.0.0/src/bspl.egg-info/PKG-INFO +372 -0
- bspl-1.0.0/src/bspl.egg-info/SOURCES.txt +71 -0
- bspl-1.0.0/src/bspl.egg-info/dependency_links.txt +1 -0
- bspl-1.0.0/src/bspl.egg-info/entry_points.txt +2 -0
- bspl-1.0.0/src/bspl.egg-info/requires.txt +26 -0
- bspl-1.0.0/src/bspl.egg-info/top_level.txt +1 -0
- bspl-1.0.0/tests/test_adapter_emissions.py +487 -0
- bspl-1.0.0/tests/test_bspl.py +122 -0
- bspl-1.0.0/tests/test_core.py +128 -0
- bspl-1.0.0/tests/test_emitter.py +53 -0
- bspl-1.0.0/tests/test_generators.py +189 -0
- bspl-1.0.0/tests/test_langshaw.py +943 -0
- bspl-1.0.0/tests/test_mambo.py +367 -0
- bspl-1.0.0/tests/test_message.py +101 -0
- bspl-1.0.0/tests/test_paths.py +138 -0
- bspl-1.0.0/tests/test_performance.py +244 -0
- bspl-1.0.0/tests/test_policies.py +145 -0
- bspl-1.0.0/tests/test_precedence.py +200 -0
- bspl-1.0.0/tests/test_protocol.py +104 -0
- bspl-1.0.0/tests/test_refinement.py +224 -0
- bspl-1.0.0/tests/test_scheduler.py +26 -0
- bspl-1.0.0/tests/test_schema.py +33 -0
- bspl-1.0.0/tests/test_statistics.py +19 -0
- bspl-1.0.0/tests/test_store.py +138 -0
- bspl-1.0.0/tests/test_verification.py +144 -0
bspl-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT/Expat License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Samuel Christie
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
bspl-1.0.0/MANIFEST.in
ADDED
bspl-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bspl
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Protocol verification tool for BSPL
|
|
5
|
+
Home-page: https://gitlab.com/masr/bspl
|
|
6
|
+
Author: Samuel Christie
|
|
7
|
+
Author-email: shcv@sdf.org
|
|
8
|
+
Project-URL: Bug Reports, https://gitlab.com/masr/bspl/-/issues
|
|
9
|
+
Project-URL: Source, https://gitlab.com/masr/bspl
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Utilities
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/plain
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: TatSu
|
|
24
|
+
Requires-Dist: simplejson
|
|
25
|
+
Requires-Dist: ttictoc
|
|
26
|
+
Requires-Dist: fire
|
|
27
|
+
Requires-Dist: aiocron
|
|
28
|
+
Requires-Dist: croniter
|
|
29
|
+
Requires-Dist: pyyaml
|
|
30
|
+
Requires-Dist: ijson
|
|
31
|
+
Requires-Dist: aiorun
|
|
32
|
+
Requires-Dist: uvloop; sys_platform != "win32"
|
|
33
|
+
Requires-Dist: colorama
|
|
34
|
+
Requires-Dist: agentspeak
|
|
35
|
+
Provides-Extra: testing
|
|
36
|
+
Requires-Dist: pytest; extra == "testing"
|
|
37
|
+
Provides-Extra: sat
|
|
38
|
+
Requires-Dist: boolexpr; extra == "sat"
|
|
39
|
+
Provides-Extra: jason
|
|
40
|
+
Requires-Dist: agentspeak; extra == "jason"
|
|
41
|
+
Provides-Extra: experiments
|
|
42
|
+
Requires-Dist: spearmint; extra == "experiments"
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
* BSPL
|
|
46
|
+
BSPL stands for the Blindingly Simple Protocol Language.
|
|
47
|
+
|
|
48
|
+
This repository provides tools for working with the language, including a parser and verification tools (proving safety, liveness, etc.)
|
|
49
|
+
It also provides a library for implementing agents that can enact BSPL protocols.
|
|
50
|
+
|
|
51
|
+
** Installation
|
|
52
|
+
BSPL may eventually be made available through the PyPI package registry, but for now install it directly from github.
|
|
53
|
+
|
|
54
|
+
*** Prerequisites
|
|
55
|
+
BSPL requires python version 3.8 or later.
|
|
56
|
+
Python 3.9+ is recommended for full compatibility with all features.
|
|
57
|
+
|
|
58
|
+
*** Install from source (Gitlab)
|
|
59
|
+
1. Download the source code from gitlab:
|
|
60
|
+
#+begin_example
|
|
61
|
+
$ git clone https://gitlab.com/masr/bspl.git
|
|
62
|
+
#+end_example
|
|
63
|
+
2. Optionally create virtual environment for BSPL
|
|
64
|
+
#+begin_example
|
|
65
|
+
$ python -m venv venv
|
|
66
|
+
#+end_example
|
|
67
|
+
3. Activate virtual environment (do this whenever you start a new shell session)
|
|
68
|
+
- Linux:
|
|
69
|
+
#+begin_example
|
|
70
|
+
$ . venv/bin/activate
|
|
71
|
+
#+end_example
|
|
72
|
+
- Windows:
|
|
73
|
+
#+begin_example
|
|
74
|
+
$ venv\Scripts\activate.bat # or venv\Scripts\Activate.ps1 in PowerShell
|
|
75
|
+
#+end_example
|
|
76
|
+
If you get an error on Windows because running script is disabled, you can fix it by running the following command:
|
|
77
|
+
#+begin_example PowerShell
|
|
78
|
+
$ Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted
|
|
79
|
+
#+end_example
|
|
80
|
+
3. Install package in development mode
|
|
81
|
+
#+begin_example
|
|
82
|
+
$ pip install -e ./bspl # or . if inside the bspl directory
|
|
83
|
+
#+end_example
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
** Usage
|
|
87
|
+
When installed globally, BSPL provides the 'bspl' entrypoint, that can be used as follows:
|
|
88
|
+
|
|
89
|
+
#+begin_example
|
|
90
|
+
SYNOPSIS
|
|
91
|
+
bspl GROUP | COMMAND - (Alternatively, python -m bspl.main on Windows)
|
|
92
|
+
|
|
93
|
+
GROUPS
|
|
94
|
+
GROUP is one of the following:
|
|
95
|
+
|
|
96
|
+
generate
|
|
97
|
+
|
|
98
|
+
verify
|
|
99
|
+
|
|
100
|
+
COMMANDS
|
|
101
|
+
COMMAND is one of the following:
|
|
102
|
+
|
|
103
|
+
ast
|
|
104
|
+
Print the parsed AST for the specification in PATH
|
|
105
|
+
|
|
106
|
+
json
|
|
107
|
+
Print a JSON representation of each protocol
|
|
108
|
+
|
|
109
|
+
check-syntax
|
|
110
|
+
Parse each file, printing any syntax errors found
|
|
111
|
+
|
|
112
|
+
load-file
|
|
113
|
+
Load a BSPL file, returning a Specification object containing one or more protocols
|
|
114
|
+
#+end_example
|
|
115
|
+
|
|
116
|
+
The CLI is implemented using the ~Fire~ library, which means that each command supports the "-h" help option to list the possible arguments.
|
|
117
|
+
Grouped commands, such as those under ~verify~, may inherit arguments from their parent, so check both.
|
|
118
|
+
|
|
119
|
+
~Fire~ enables inspection and chaining of function results, such as with the ~load-file~ command for loading a specification.
|
|
120
|
+
After the specification is loaded, you can inspect its contents and call methods on them, etc.
|
|
121
|
+
|
|
122
|
+
~Fire~ can also launch a python shell with various objects available via ~-- --interactive~.
|
|
123
|
+
For example, try ~bspl load-file samples/trade-finance/purchase.bspl protocols Purchase -- --interactive~, and you should get a python REPL with the Purchase protocol loaded in the ~result~ variable.
|
|
124
|
+
|
|
125
|
+
There are some example protocol files in the 'samples' directory.
|
|
126
|
+
|
|
127
|
+
*** Notes
|
|
128
|
+
- There are probably still some bugs. If you find a case that doesn't work as you expect, please submit an issue.
|
|
129
|
+
- For easier testing of listings used in latex papers, BSPL will automatically strip some latex formatting before parsing a protocol, so they should work without modification.
|
|
130
|
+
|
|
131
|
+
** Implementing Agents
|
|
132
|
+
This repository provides a /protocol adapter/ for implementing agents that play roles in a BSPL protocol.
|
|
133
|
+
|
|
134
|
+
You can run the scenario implementation using the ~start.sh~ script (or ~start.ps1~ on Windows) to launch all of the agents at the same time; press any key to kill them and stop the run.
|
|
135
|
+
|
|
136
|
+
*** Specifying the Protocol
|
|
137
|
+
Our tutorial will follow the Logistics scenario, visible in the scenarios directory.
|
|
138
|
+
|
|
139
|
+
The protocol could be provided as an object in the python code directly, but it is generally easier to specify it as a separate BSPL file and then load it in the agent.
|
|
140
|
+
The protocol we will be using is as follows, given in logistics.bspl:
|
|
141
|
+
#+begin_src bspl
|
|
142
|
+
Logistics {
|
|
143
|
+
roles Merchant, Wrapper, Labeler, Packer
|
|
144
|
+
parameters out orderID key, out itemID key, out item, out status
|
|
145
|
+
private address, label, wrapping
|
|
146
|
+
|
|
147
|
+
Merchant -> Labeler: RequestLabel[out orderID key, out address]
|
|
148
|
+
Merchant -> Wrapper: RequestWrapping[in orderID key, out itemID key, out item]
|
|
149
|
+
Wrapper -> Packer: Wrapped[in orderID key, in itemID key, in item, out wrapping]
|
|
150
|
+
Labeler -> Packer: Labeled[in orderID key, in address, out label]
|
|
151
|
+
Packer -> Merchant: Packed[in orderID key, in itemID key, in wrapping, in label, out status]
|
|
152
|
+
}
|
|
153
|
+
#+end_src
|
|
154
|
+
|
|
155
|
+
This protocol describes roles for four agents, each of which can be implemented either using Python decorators or AgentSpeak (ASL).
|
|
156
|
+
|
|
157
|
+
*** Loading and Configuring the Protocol
|
|
158
|
+
First, load the protocol and export it as a module:
|
|
159
|
+
#+begin_src python
|
|
160
|
+
import bspl
|
|
161
|
+
logistics = bspl.load_file("logistics.bspl").export("Logistics")
|
|
162
|
+
from Logistics import Merchant, Wrapper, Labeler, Packer
|
|
163
|
+
from Logistics import RequestLabel, RequestWrapping, Packed
|
|
164
|
+
#+end_src
|
|
165
|
+
|
|
166
|
+
*** Configuring the Agent
|
|
167
|
+
After loading its protocol, role, and possibly messages, each agent will need to be configured with information about how to connect to the other agents.
|
|
168
|
+
|
|
169
|
+
In the logistics scenario, all of this is done in a common configuration.py file that can be loaded by all four of the agents, but they could be configured separately.
|
|
170
|
+
|
|
171
|
+
#+begin_src python
|
|
172
|
+
agents = {
|
|
173
|
+
"Merchant": [("127.0.0.1", 8000)],
|
|
174
|
+
"Wrapper": [("127.0.0.1", 8001)],
|
|
175
|
+
"Labeler": [("127.0.0.1", 8002)],
|
|
176
|
+
"Packer": [("127.0.0.1", 8003)],
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
systems = {
|
|
180
|
+
"logistics": {
|
|
181
|
+
"protocol": logistics,
|
|
182
|
+
"roles": {
|
|
183
|
+
Merchant: "Merchant",
|
|
184
|
+
Wrapper: "Wrapper",
|
|
185
|
+
Labeler: "Labeler",
|
|
186
|
+
Packer: "Packer",
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
#+end_src
|
|
191
|
+
The role binding configuration is a single dictionary mapping roles to tuples containing (IP, port) pairs.
|
|
192
|
+
They don't all have to be on the same machine, but in this example we are running them all on localhost (127.0.0.1)
|
|
193
|
+
The configuration that each agent sees for itself identifies what IP address and port it should listen on; 127.0.0.1 is chosen here so that they listen on all IPs known to the host networking system.
|
|
194
|
+
|
|
195
|
+
*** Implementing Agent Behavior
|
|
196
|
+
There are two approaches to implementing agent behavior in BSPL:
|
|
197
|
+
|
|
198
|
+
**** Approach 1: Using Python Decorators
|
|
199
|
+
This approach is straightforward for request-response patterns and is used in the logistics scenario.
|
|
200
|
+
|
|
201
|
+
***** Setting up the Agent
|
|
202
|
+
First, create the basic agent structure:
|
|
203
|
+
|
|
204
|
+
#+begin_src python
|
|
205
|
+
import logging
|
|
206
|
+
from bspl.adapter import Adapter
|
|
207
|
+
from configuration import systems, agents
|
|
208
|
+
from Logistics import RequestLabel, RequestWrapping, Packed
|
|
209
|
+
|
|
210
|
+
adapter = Adapter("Merchant", systems, agents)
|
|
211
|
+
logger = logging.getLogger("merchant")
|
|
212
|
+
if __name__ == "__main__":
|
|
213
|
+
logger.info("Starting Merchant...")
|
|
214
|
+
adapter.start()
|
|
215
|
+
#+end_src
|
|
216
|
+
|
|
217
|
+
***** Acting Proactively
|
|
218
|
+
To start an enactment of a protocol, some agent will have to make the first move. In Logistics, that's the Merchant, who requests the wrapping and labeling of the items in an order. This can be seen from the first message in the protocol, RequestLabel, which has all its parameters labeled ~out~, which means it has no dependencies and can be sent at will.
|
|
219
|
+
|
|
220
|
+
#+begin_src python
|
|
221
|
+
async def order_generator():
|
|
222
|
+
"""Generates sample orders."""
|
|
223
|
+
for orderID in range(10):
|
|
224
|
+
await adapter.send(
|
|
225
|
+
RequestLabel(
|
|
226
|
+
orderID=orderID,
|
|
227
|
+
address=random.choice(["Lancaster University", "NCSU"]),
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
for i in range(2):
|
|
231
|
+
await adapter.send(
|
|
232
|
+
RequestWrapping(
|
|
233
|
+
orderID=orderID,
|
|
234
|
+
itemID=i,
|
|
235
|
+
item=random.choice(["ball", "bat", "plate", "glass"]),
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
await asyncio.sleep(0)
|
|
239
|
+
#+end_src
|
|
240
|
+
|
|
241
|
+
A lot of new things here:
|
|
242
|
+
- The function is asynchronous, to work with the adapter
|
|
243
|
+
- Messages are constructed by passing in their parameters as keyword arguments
|
|
244
|
+
- The resulting message instances are sent with ~adapter.send(message)~
|
|
245
|
+
- There's an ~asyncio.sleep(0)~ step near the end to make sure it doesn't all happen instantly
|
|
246
|
+
|
|
247
|
+
***** Adding a Reactor
|
|
248
|
+
In most protocols, not all messages are sent independently. Instead, many have dependencies and may follow a simple request/response pattern. We can handle these using a reactor:
|
|
249
|
+
|
|
250
|
+
#+begin_src python
|
|
251
|
+
@adapter.reaction(Packed)
|
|
252
|
+
async def packed(msg):
|
|
253
|
+
"""Handle packed items."""
|
|
254
|
+
logger.info(f"Order {msg['orderID']} item {msg['itemID']} packed with status: {msg['status']}")
|
|
255
|
+
return msg
|
|
256
|
+
|
|
257
|
+
if __name__ == "__main__":
|
|
258
|
+
adapter.start(order_generator())
|
|
259
|
+
#+end_src
|
|
260
|
+
|
|
261
|
+
The reactor is registered using the ~@adapter.reaction~ decorator and is called whenever a matching message is received. The message instance is passed as a parameter, containing all the message's data.
|
|
262
|
+
|
|
263
|
+
**** Approach 2: Using AgentSpeak (ASL)
|
|
264
|
+
For more complex behaviors with interdependent states, you can use ASL files. The BSPL compiler can generate ASL templates for your protocol:
|
|
265
|
+
|
|
266
|
+
#+begin_src bash
|
|
267
|
+
python -m bspl.main generate asl logistics.bspl --all_roles
|
|
268
|
+
#+end_src
|
|
269
|
+
|
|
270
|
+
This generates basic ASL files that need to be enhanced with business logic. Here's an example of the generated vs. working code for the Wrapper role:
|
|
271
|
+
|
|
272
|
+
Generated template:
|
|
273
|
+
#+begin_src asl
|
|
274
|
+
+request_wrapping(MasID, Merchant, Wrapper, OrderID, ItemID, Item)
|
|
275
|
+
<- // insert code to compute Wrapped out parameters ['wrapping'] here
|
|
276
|
+
.emit(wrapped(MasID, Wrapper, Packer, OrderID, ItemID, Item, Wrapping)).
|
|
277
|
+
#+end_src
|
|
278
|
+
|
|
279
|
+
Working implementation:
|
|
280
|
+
#+begin_src asl
|
|
281
|
+
+request_wrapping(System, Merchant, Wrapper, OrderID, ItemID, Item)
|
|
282
|
+
<- // Generate wrapping based on item
|
|
283
|
+
if (Item == "ball") {
|
|
284
|
+
Wrapping = "box"
|
|
285
|
+
} else {
|
|
286
|
+
if (Item == "bat") {
|
|
287
|
+
Wrapping = "tube"
|
|
288
|
+
} else {
|
|
289
|
+
if (Item == "plate") {
|
|
290
|
+
Wrapping = "bubble wrap"
|
|
291
|
+
} else {
|
|
292
|
+
Wrapping = "foam"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
.print("Wrapper: Using ", Wrapping, " for item ", Item, " (Order ", OrderID, ")");
|
|
297
|
+
.emit(wrapped(System, Wrapper, "Packer", OrderID, ItemID, Item, Wrapping)).
|
|
298
|
+
#+end_src
|
|
299
|
+
|
|
300
|
+
Key changes needed to make generated ASL files work:
|
|
301
|
+
1. Replace ~MasID~ with ~System~ for protocol identification
|
|
302
|
+
2. Add concrete business logic to compute output parameters
|
|
303
|
+
3. Use string literals for known role names (e.g., ~"Packer"~)
|
|
304
|
+
4. Add logging for better visibility of the protocol execution
|
|
305
|
+
|
|
306
|
+
***** Setting up an ASL Agent
|
|
307
|
+
The Python code for an ASL agent is much simpler than the decorator approach:
|
|
308
|
+
|
|
309
|
+
#+begin_src python
|
|
310
|
+
from bspl.adapter import Adapter
|
|
311
|
+
from configuration import systems, agents
|
|
312
|
+
|
|
313
|
+
adapter = Adapter("Wrapper", systems, agents)
|
|
314
|
+
adapter.load_asl("wrapper.asl")
|
|
315
|
+
|
|
316
|
+
if __name__ == "__main__":
|
|
317
|
+
print("Starting Wrapper...")
|
|
318
|
+
adapter.start()
|
|
319
|
+
#+end_src
|
|
320
|
+
|
|
321
|
+
***** Complex Coordination Example
|
|
322
|
+
The Packer role demonstrates how ASL handles complex coordination between multiple messages:
|
|
323
|
+
|
|
324
|
+
#+begin_src asl
|
|
325
|
+
// Handle wrapped item
|
|
326
|
+
+wrapped(System, Wrapper, Packer, OrderID, ItemID, Item, Wrapping)
|
|
327
|
+
: labeled(System, Labeler, Packer, OrderID, Address, Label)
|
|
328
|
+
<- !send_packed(System, Packer, "Merchant", OrderID, ItemID, Item, Wrapping, Label).
|
|
329
|
+
|
|
330
|
+
// Handle labeled item
|
|
331
|
+
+labeled(System, Labeler, Packer, OrderID, Address, Label)
|
|
332
|
+
: wrapped(System, Wrapper, Packer, OrderID, ItemID, Item, Wrapping)
|
|
333
|
+
<- !send_packed(System, Packer, "Merchant", OrderID, ItemID, Item, Wrapping, Label).
|
|
334
|
+
|
|
335
|
+
// Send packed item
|
|
336
|
+
+!send_packed(System, Packer, Merchant, OrderID, ItemID, Item, Wrapping, Label)
|
|
337
|
+
<- // Generate status based on wrapping and label
|
|
338
|
+
if (Wrapping == "box" & Label == "UK-LANCS-001") {
|
|
339
|
+
Status = "ready for UK shipping"
|
|
340
|
+
} else {
|
|
341
|
+
if (Wrapping == "box" & Label == "US-NCSU-001") {
|
|
342
|
+
Status = "ready for US shipping"
|
|
343
|
+
} else {
|
|
344
|
+
Status = "ready for shipping"
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
.print("Packer: Item ", Item, " from order ", OrderID, " is ", Status);
|
|
348
|
+
.emit(packed(System, Packer, Merchant, OrderID, ItemID, Item, Wrapping, Label, Status)).
|
|
349
|
+
#+end_src
|
|
350
|
+
|
|
351
|
+
The Packer waits for both ~wrapped~ and ~labeled~ messages before sending the ~packed~ message, using ASL's context conditions (~:~) to ensure proper synchronization.
|
|
352
|
+
|
|
353
|
+
*** Choosing an Approach
|
|
354
|
+
- Use Python decorators (like in logistics/) when:
|
|
355
|
+
- You have simple request-response patterns
|
|
356
|
+
- You want straightforward, procedural code
|
|
357
|
+
- You need to integrate with Python libraries
|
|
358
|
+
|
|
359
|
+
- Use ASL files (like in grading/) when:
|
|
360
|
+
- You need complex rule-based behavior
|
|
361
|
+
- Your agent has many interdependent states
|
|
362
|
+
- You want a more declarative programming style
|
|
363
|
+
|
|
364
|
+
*** Running the Scenario
|
|
365
|
+
The ~start.sh~ script (or ~start.ps1~ on Windows) launches all agents:
|
|
366
|
+
#+begin_src bash
|
|
367
|
+
./start.sh
|
|
368
|
+
# On Windows:
|
|
369
|
+
# ./start.ps1
|
|
370
|
+
#+end_src
|
|
371
|
+
|
|
372
|
+
This will start all agents and begin processing orders. Press any key to stop the scenario.
|