agi-app-uav-relay-queue 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.
- agi_app_uav_relay_queue-0.1.0/LICENSE +22 -0
- agi_app_uav_relay_queue-0.1.0/PKG-INFO +49 -0
- agi_app_uav_relay_queue-0.1.0/README.md +19 -0
- agi_app_uav_relay_queue-0.1.0/pyproject.toml +84 -0
- agi_app_uav_relay_queue-0.1.0/setup.cfg +4 -0
- agi_app_uav_relay_queue-0.1.0/setup.py +47 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/__init__.py +33 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/README.md +64 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/lab_stages.toml +4 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/notebook_export.toml +26 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/pipeline_view.dot +13 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/pyproject.toml +13 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/service_templates/train_then_serve_policy_run.json +65 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/app_args_form.py +163 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/app_settings.toml +54 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/connectors/data_connectors.toml +27 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/pre_prompt.json +1 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue/__init__.py +30 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue/app_args.py +94 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue/reduction.py +204 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue/sample_data/uav_queue_hotspot.json +50 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue/uav_relay_queue.py +143 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue/uav_relay_queue_alias.py +5 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue/uav_relay_queue_args.py +23 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue_worker/__init__.py +5 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue_worker/pyproject.toml +13 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/src/uav_relay_queue_worker/uav_relay_queue_worker.py +713 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/uv_config.toml +5 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/PKG-INFO +49 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/SOURCES.txt +11 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/dependency_links.txt +1 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/entry_points.txt +3 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/requires.txt +1 -0
- agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Jean-Pierre Morard, THALES SIX GTS France SAS
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
|
7
|
+
following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
|
10
|
+
disclaimer.
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
12
|
+
disclaimer in the documentation and/or other materials provided with the distribution.
|
|
13
|
+
3. Neither the name of Jean-Pierre MORARD nor the names of its contributors, or THALES SIX GTS France SAS, may be used
|
|
14
|
+
to endorse or promote products derived from this software without specific prior written permission.
|
|
15
|
+
|
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
17
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
19
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
20
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
21
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
22
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agi-app-uav-relay-queue
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AGILAB UAV relay queue app project
|
|
5
|
+
Author: Jean-Pierre Morard
|
|
6
|
+
Maintainer: Jean-Pierre Morard
|
|
7
|
+
License-Expression: BSD-3-Clause
|
|
8
|
+
Project-URL: Documentation, https://thalesgroup.github.io/agilab
|
|
9
|
+
Project-URL: Source, https://github.com/ThalesGroup/agilab/tree/main/src/agilab/lib/agi-app-uav-relay-queue
|
|
10
|
+
Project-URL: Issues, https://github.com/ThalesGroup/agilab/issues
|
|
11
|
+
Project-URL: Homepage, https://github.com/ThalesGroup/agilab
|
|
12
|
+
Project-URL: Repository, https://github.com/ThalesGroup/agilab
|
|
13
|
+
Project-URL: Discussions, https://github.com/ThalesGroup/agilab/discussions
|
|
14
|
+
Project-URL: Changelog, https://github.com/ThalesGroup/agilab/releases
|
|
15
|
+
Keywords: agilab,apps,reproducibility,workflow-orchestration
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Development Status :: 4 - Beta
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Operating System :: MacOS
|
|
23
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
24
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: agi-core<2027.0,>=2026.05.13
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# agi-app-uav-relay-queue
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/agi-app-uav-relay-queue/)
|
|
34
|
+
[](https://pypi.org/project/agi-app-uav-relay-queue/)
|
|
35
|
+
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
36
|
+
|
|
37
|
+
`agi-app-uav-relay-queue` publishes the `uav_relay_queue_project` AGILAB app project as a self-contained
|
|
38
|
+
package payload. The package advertises the project through the `agilab.apps`
|
|
39
|
+
entry point group so `AgiEnv(app="uav_relay_queue_project")` can resolve it without a
|
|
40
|
+
monorepo checkout.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install agi-app-uav-relay-queue
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Most users install these app packages through the umbrella `agi-apps` package or
|
|
49
|
+
through `agilab[ui]` / `agilab[examples]`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# agi-app-uav-relay-queue
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/agi-app-uav-relay-queue/)
|
|
4
|
+
[](https://pypi.org/project/agi-app-uav-relay-queue/)
|
|
5
|
+
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
6
|
+
|
|
7
|
+
`agi-app-uav-relay-queue` publishes the `uav_relay_queue_project` AGILAB app project as a self-contained
|
|
8
|
+
package payload. The package advertises the project through the `agilab.apps`
|
|
9
|
+
entry point group so `AgiEnv(app="uav_relay_queue_project")` can resolve it without a
|
|
10
|
+
monorepo checkout.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install agi-app-uav-relay-queue
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Most users install these app packages through the umbrella `agi-apps` package or
|
|
19
|
+
through `agilab[ui]` / `agilab[examples]`.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
version = "0.1.0"
|
|
3
|
+
name = "agi-app-uav-relay-queue"
|
|
4
|
+
description = "AGILAB UAV relay queue app project"
|
|
5
|
+
requires-python = ">=3.11"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Jean-Pierre Morard" }
|
|
9
|
+
]
|
|
10
|
+
maintainers = [{ name = "Jean-Pierre Morard" }]
|
|
11
|
+
license = "BSD-3-Clause"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Operating System :: MacOS",
|
|
22
|
+
"Operating System :: Microsoft :: Windows",
|
|
23
|
+
"Operating System :: POSIX :: Linux",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
keywords = [
|
|
27
|
+
"agilab",
|
|
28
|
+
"apps",
|
|
29
|
+
"reproducibility",
|
|
30
|
+
"workflow-orchestration",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
dependencies = ["agi-core>=2026.05.13,<2027.0"]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Documentation = "https://thalesgroup.github.io/agilab"
|
|
37
|
+
Source = "https://github.com/ThalesGroup/agilab/tree/main/src/agilab/lib/agi-app-uav-relay-queue"
|
|
38
|
+
Issues = "https://github.com/ThalesGroup/agilab/issues"
|
|
39
|
+
Homepage = "https://github.com/ThalesGroup/agilab"
|
|
40
|
+
Repository = "https://github.com/ThalesGroup/agilab"
|
|
41
|
+
Discussions = "https://github.com/ThalesGroup/agilab/discussions"
|
|
42
|
+
Changelog = "https://github.com/ThalesGroup/agilab/releases"
|
|
43
|
+
|
|
44
|
+
[project.entry-points."agilab.apps"]
|
|
45
|
+
uav_relay_queue = "agi_app_uav_relay_queue:project_root"
|
|
46
|
+
uav_relay_queue_project = "agi_app_uav_relay_queue:project_root"
|
|
47
|
+
|
|
48
|
+
[dependency-groups]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.uv.sources.agi-core]
|
|
54
|
+
path = "../../core/agi-core"
|
|
55
|
+
editable = true
|
|
56
|
+
|
|
57
|
+
[build-system]
|
|
58
|
+
requires = ["setuptools>=68", "wheel"]
|
|
59
|
+
build-backend = "setuptools.build_meta"
|
|
60
|
+
|
|
61
|
+
[tool.setuptools]
|
|
62
|
+
include-package-data = false
|
|
63
|
+
package-dir = {"" = "src"}
|
|
64
|
+
packages = ["agi_app_uav_relay_queue"]
|
|
65
|
+
|
|
66
|
+
[tool.setuptools.package-data]
|
|
67
|
+
"agi_app_uav_relay_queue" = [
|
|
68
|
+
"project/**/*",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[tool.setuptools.exclude-package-data]
|
|
72
|
+
"agi_app_uav_relay_queue" = [
|
|
73
|
+
"project/**/.venv/**",
|
|
74
|
+
"project/**/__pycache__/**",
|
|
75
|
+
"project/**/*.pyc",
|
|
76
|
+
"project/**/*.pyo",
|
|
77
|
+
"project/**/*.pyx",
|
|
78
|
+
"project/**/*.c",
|
|
79
|
+
"project/**/*.so",
|
|
80
|
+
"project/**/uv.lock",
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
[tool.pytest.ini_options]
|
|
84
|
+
testpaths = ["test"]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from setuptools import setup
|
|
7
|
+
from setuptools.command.build_py import build_py as _build_py
|
|
8
|
+
from setuptools.command.sdist import sdist as _sdist
|
|
9
|
+
|
|
10
|
+
APP_PROJECT = 'uav_relay_queue_project'
|
|
11
|
+
PACKAGE_IMPORT = 'agi_app_uav_relay_queue'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _load_build_support():
|
|
15
|
+
module_path = Path(__file__).resolve().parents[4] / "src" / "agilab" / "lib" / "app_project_build_support.py"
|
|
16
|
+
if not module_path.exists():
|
|
17
|
+
return None
|
|
18
|
+
spec = importlib.util.spec_from_file_location("agilab_app_project_build_support", module_path)
|
|
19
|
+
if spec is None or spec.loader is None:
|
|
20
|
+
raise RuntimeError(f"Unable to load app project build support from {module_path}")
|
|
21
|
+
module = importlib.util.module_from_spec(spec)
|
|
22
|
+
spec.loader.exec_module(module)
|
|
23
|
+
return module
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _copy_payload(target_root: Path) -> None:
|
|
27
|
+
support = _load_build_support()
|
|
28
|
+
if support is None:
|
|
29
|
+
return
|
|
30
|
+
changed = support.copy_app_project_payload(APP_PROJECT, target_root)
|
|
31
|
+
for pyproject_path in changed:
|
|
32
|
+
print(f"[{PACKAGE_IMPORT}] sanitized packaged app manifest: {pyproject_path}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class build_py(_build_py):
|
|
36
|
+
def run(self):
|
|
37
|
+
super().run()
|
|
38
|
+
_copy_payload(Path(self.build_lib) / PACKAGE_IMPORT / "project")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class sdist(_sdist):
|
|
42
|
+
def make_release_tree(self, base_dir, files):
|
|
43
|
+
super().make_release_tree(base_dir, files)
|
|
44
|
+
_copy_payload(Path(base_dir) / "src" / PACKAGE_IMPORT / "project")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
setup(cmdclass={"build_py": build_py, "sdist": sdist})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Installed AGILAB app project provider for uav_relay_queue_project."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
APP_SLUG = 'uav_relay_queue'
|
|
8
|
+
PROJECT_NAME = 'uav_relay_queue_project'
|
|
9
|
+
PACKAGE_NAME = 'agi-app-uav-relay-queue'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def package_root() -> Path:
|
|
13
|
+
return Path(__file__).resolve().parent
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def project_root() -> Path:
|
|
17
|
+
packaged_root = package_root() / "project" / PROJECT_NAME
|
|
18
|
+
if packaged_root.exists():
|
|
19
|
+
return packaged_root
|
|
20
|
+
source_root = Path(__file__).resolve().parents[4] / "apps" / "builtin" / PROJECT_NAME
|
|
21
|
+
return source_root if source_root.exists() else packaged_root
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def metadata() -> dict[str, str]:
|
|
25
|
+
return {
|
|
26
|
+
"slug": APP_SLUG,
|
|
27
|
+
"project": PROJECT_NAME,
|
|
28
|
+
"package": PACKAGE_NAME,
|
|
29
|
+
"project_root": str(project_root()),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
__all__ = ["APP_SLUG", "PACKAGE_NAME", "PROJECT_NAME", "metadata", "package_root", "project_root"]
|
agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# UAV Relay Queue Project
|
|
2
|
+
|
|
3
|
+
`uav_relay_queue_project` is the AGILAB install id for this built-in lightweight UAV
|
|
4
|
+
relay queue example.
|
|
5
|
+
|
|
6
|
+
The project demonstrates a compact routing-and-queueing simulation:
|
|
7
|
+
- one UAV source
|
|
8
|
+
- one ground sink
|
|
9
|
+
- two relay choices with different queue and delay trade-offs
|
|
10
|
+
- exported telemetry that can be inspected in AGILAB analysis pages
|
|
11
|
+
|
|
12
|
+
Origin note:
|
|
13
|
+
|
|
14
|
+
- this built-in example is conceptually inspired by the SimPy buffer-based
|
|
15
|
+
queueing pattern described in
|
|
16
|
+
[`UavNetSim`](https://github.com/Zihao-Felix-Zhou/UavNetSim)
|
|
17
|
+
(MIT-licensed)
|
|
18
|
+
- it does not vendor or claim to adapt UavNetSim source code directly
|
|
19
|
+
|
|
20
|
+
## What it is good for
|
|
21
|
+
|
|
22
|
+
- a self-contained AGILAB demo app
|
|
23
|
+
- quick queue-aware routing experiments
|
|
24
|
+
- understanding how relay congestion changes packet delivery, delay, and queue depth
|
|
25
|
+
|
|
26
|
+
## What is not implemented in the public version
|
|
27
|
+
|
|
28
|
+
This public built-in example is intentionally lightweight. It does **not** implement:
|
|
29
|
+
- a full external UAV network simulator or emulator backend
|
|
30
|
+
- detailed radio, PHY, or MAC behavior
|
|
31
|
+
- large topology families or operational-scale routing stacks
|
|
32
|
+
- production-grade routing control traffic, interference, or energy models
|
|
33
|
+
- a complete research benchmark for UAV networking
|
|
34
|
+
|
|
35
|
+
The goal is to keep the public example easy to run while still making queue buildup,
|
|
36
|
+
relay choice, delay, and drops visible inside AGILAB.
|
|
37
|
+
|
|
38
|
+
## Main outputs
|
|
39
|
+
|
|
40
|
+
Each run exports:
|
|
41
|
+
- queue time series
|
|
42
|
+
- packet events
|
|
43
|
+
- relay routing summary
|
|
44
|
+
- node positions
|
|
45
|
+
- `pipeline/topology.gml`
|
|
46
|
+
- `pipeline/allocations_steps.csv`
|
|
47
|
+
- trajectory CSVs for `view_maps_network`
|
|
48
|
+
|
|
49
|
+
## Typical flow
|
|
50
|
+
|
|
51
|
+
1. Select `uav_relay_queue_project` in `PROJECT`.
|
|
52
|
+
2. Run it from `ORCHESTRATE`.
|
|
53
|
+
3. Inspect queue artifacts in `view_relay_resilience`.
|
|
54
|
+
4. Inspect topology and trajectories in `view_maps_network`.
|
|
55
|
+
|
|
56
|
+
## What this teases in AGILAB
|
|
57
|
+
|
|
58
|
+
The same framework can support richer network studies than this public demo shows.
|
|
59
|
+
With dedicated apps and pages, AGILAB can be used to:
|
|
60
|
+
- run larger scenario sweeps through `ORCHESTRATE` and `WORKFLOW`
|
|
61
|
+
- attach custom analysis pages to domain-specific artifacts
|
|
62
|
+
- compare routing variants across repeatable experiment runs
|
|
63
|
+
- distribute experiments across workers instead of keeping everything local
|
|
64
|
+
- evolve a lightweight demo into a more advanced simulator-backed workflow
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
uav_relay_queue = [
|
|
2
|
+
{ D = "Seed the UAV relay queue scenario", Q = "Load or seed the compact UAV relay queue scenario and expose two relay paths toward one sink.", M = "", C = "APP = 'uav_relay_queue_project'\nscenario = 'uav_queue_hotspot'\nrouting_policy = 'shortest_path'", R = "runpy" },
|
|
3
|
+
{ D = "Run the relay queue policy", Q = "Execute the chosen relay policy and export packet, queue, and trajectory artifacts for analysis.", M = "", C = "APP = 'uav_relay_queue_project'\nrouting_policy = 'queue_aware'\ndata_in = 'uav_relay_queue/scenarios'\ndata_out = 'uav_relay_queue/results'", R = "runpy" },
|
|
4
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[notebook_export]
|
|
2
|
+
|
|
3
|
+
[[notebook_export.related_pages]]
|
|
4
|
+
module = "view_relay_resilience"
|
|
5
|
+
label = "UAV Relay Queue Analysis"
|
|
6
|
+
description = "Inspect queue depth, packet delivery, relay routing summary, and node positions for the relay-queue demo."
|
|
7
|
+
artifacts = [
|
|
8
|
+
"*_summary_metrics.json",
|
|
9
|
+
"*_queue_timeseries.csv",
|
|
10
|
+
"*_packet_events.csv",
|
|
11
|
+
"*_node_positions.csv",
|
|
12
|
+
"*_routing_summary.csv",
|
|
13
|
+
]
|
|
14
|
+
launch_note = "Open this first for the dedicated relay queue analysis view over the exported run artifacts."
|
|
15
|
+
|
|
16
|
+
[[notebook_export.related_pages]]
|
|
17
|
+
module = "view_maps_network"
|
|
18
|
+
label = "Maps Network"
|
|
19
|
+
description = "Reuse the same relay run as a topology, allocation, and trajectory map."
|
|
20
|
+
artifacts = [
|
|
21
|
+
"pipeline/topology.gml",
|
|
22
|
+
"pipeline/allocations_steps.csv",
|
|
23
|
+
"*_trajectory_summary.json",
|
|
24
|
+
"*_trajectory*.csv",
|
|
25
|
+
]
|
|
26
|
+
launch_note = "Use this when you want the generic topology and trajectory exploration path for the same run."
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
digraph uav_relay_queue_pipeline {
|
|
2
|
+
rankdir=LR;
|
|
3
|
+
graph [fontname="Helvetica", fontsize=10];
|
|
4
|
+
node [shape=box, style="rounded,filled", fillcolor="#F5F7FA", color="#2F4B7C", fontname="Helvetica", fontsize=10];
|
|
5
|
+
edge [color="#4C78A8", arrowsize=0.8];
|
|
6
|
+
|
|
7
|
+
scenario [label="Scenario JSON\nsource + relays + sink"];
|
|
8
|
+
simulate [label="UAV relay queue simulation\nshortest_path | queue_aware"];
|
|
9
|
+
analysis [label="AGILAB ANALYSIS\nview_relay_resilience\nview_maps_network"];
|
|
10
|
+
|
|
11
|
+
scenario -> simulate;
|
|
12
|
+
simulate -> analysis;
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "uav_relay_queue_project"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Built-in AGILAB lightweight UAV relay queue example"
|
|
5
|
+
requires-python = ">=3.13"
|
|
6
|
+
dependencies = ["agi-env>=2026.05.13.post3,<2027.0", "agi-node>=2026.05.13.post3,<2027.0", "agi-cluster>=2026.05.13.post3,<2027.0", "networkx", "pandas>=2.3.0", "pydantic", "simpy>=4.1,<5", "streamlit>=1.56.0"]
|
|
7
|
+
|
|
8
|
+
[tool.setuptools.package-data]
|
|
9
|
+
uav_relay_queue = ["sample_data/*.json"]
|
|
10
|
+
|
|
11
|
+
[build-system]
|
|
12
|
+
requires = ["setuptools"]
|
|
13
|
+
build-backend = "setuptools.build_meta"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "agilab.example.train_then_serve.v1",
|
|
3
|
+
"training_run": {
|
|
4
|
+
"app": "sb3_trainer_project",
|
|
5
|
+
"trainer": "uav_relay_queue_ppo",
|
|
6
|
+
"run_id": "trainer_uav_relay_queue_ppo_preview",
|
|
7
|
+
"model_artifact": "sb3_trainer/pipeline/trainer_uav_relay_queue_ppo/uav_queue_model.zip",
|
|
8
|
+
"metrics": {
|
|
9
|
+
"delivery_ratio": 0.96,
|
|
10
|
+
"p95_latency_ms": 61.0,
|
|
11
|
+
"reward_mean": 42.5
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"service": {
|
|
15
|
+
"name": "uav_relay_policy_service",
|
|
16
|
+
"version": "2026.05.preview",
|
|
17
|
+
"health_thresholds": {
|
|
18
|
+
"latency_budget_ms": 80.0,
|
|
19
|
+
"allow_idle": false,
|
|
20
|
+
"max_unhealthy": 0,
|
|
21
|
+
"max_restart_rate": 0.25
|
|
22
|
+
},
|
|
23
|
+
"input_schema": {
|
|
24
|
+
"source_queue_depth": "float 0..1",
|
|
25
|
+
"candidate_relays": "list of relay features"
|
|
26
|
+
},
|
|
27
|
+
"output_schema": {
|
|
28
|
+
"selected_relay": "relay id",
|
|
29
|
+
"action": "route_via_relay",
|
|
30
|
+
"confidence": "float 0..1"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"prediction_request": {
|
|
34
|
+
"source_queue_depth": 0.82,
|
|
35
|
+
"candidate_relays": [
|
|
36
|
+
{
|
|
37
|
+
"id": "relay_alpha",
|
|
38
|
+
"latency_ms": 72.0,
|
|
39
|
+
"queue_depth": 0.74,
|
|
40
|
+
"capacity_mbps": 7.5,
|
|
41
|
+
"risk": 0.22
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "relay_beta",
|
|
45
|
+
"latency_ms": 55.0,
|
|
46
|
+
"queue_depth": 0.41,
|
|
47
|
+
"capacity_mbps": 9.4,
|
|
48
|
+
"risk": 0.11
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "relay_gamma",
|
|
52
|
+
"latency_ms": 63.0,
|
|
53
|
+
"queue_depth": 0.35,
|
|
54
|
+
"capacity_mbps": 8.1,
|
|
55
|
+
"risk": 0.08
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"policy_scoring": {
|
|
60
|
+
"capacity_mbps": 0.42,
|
|
61
|
+
"latency_ms": -0.18,
|
|
62
|
+
"queue_depth": -0.28,
|
|
63
|
+
"risk": -0.12
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import sys
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import streamlit as st
|
|
8
|
+
from pydantic import ValidationError
|
|
9
|
+
|
|
10
|
+
_HERE = Path(__file__).resolve().parent
|
|
11
|
+
if str(_HERE) not in sys.path:
|
|
12
|
+
sys.path.insert(0, str(_HERE))
|
|
13
|
+
|
|
14
|
+
from uav_relay_queue import UavRelayQueueArgs, dump_args, load_args
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
PAGE_ID = "uav_relay_queue_project:app_args_form"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _k(name: str) -> str:
|
|
21
|
+
return f"{PAGE_ID}:{name}"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _get_env():
|
|
25
|
+
env = st.session_state.get("env") or st.session_state.get("_env")
|
|
26
|
+
if env is None:
|
|
27
|
+
st.error("AGILab environment is not initialised yet. Return to the main page and try again.")
|
|
28
|
+
st.stop()
|
|
29
|
+
return env
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _load_current_args(settings_path: Path) -> UavRelayQueueArgs:
|
|
33
|
+
try:
|
|
34
|
+
return load_args(settings_path)
|
|
35
|
+
except Exception as exc:
|
|
36
|
+
st.warning(f"Unable to load UAV relay queue args from `{settings_path}`: {exc}")
|
|
37
|
+
return UavRelayQueueArgs()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
env = _get_env()
|
|
41
|
+
settings_path = Path(env.app_settings_file)
|
|
42
|
+
current_args = _load_current_args(settings_path)
|
|
43
|
+
current_payload = current_args.model_dump(mode="json")
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
share_root = env.share_root_path()
|
|
47
|
+
except Exception:
|
|
48
|
+
share_root = None
|
|
49
|
+
|
|
50
|
+
artifact_root = Path(getattr(env, "AGILAB_EXPORT_ABS", Path.home() / "export")) / env.target / "queue_analysis"
|
|
51
|
+
|
|
52
|
+
st.caption(
|
|
53
|
+
"This built-in app runs a lightweight UAV relay queue simulation with explicit "
|
|
54
|
+
f"packet and queue telemetry. Analysis artifacts are exported to `{artifact_root}`."
|
|
55
|
+
)
|
|
56
|
+
if share_root:
|
|
57
|
+
st.caption(f"Current shared root: `{share_root}`")
|
|
58
|
+
|
|
59
|
+
defaults = {
|
|
60
|
+
"data_in": str(current_payload.get("data_in", "") or ""),
|
|
61
|
+
"data_out": str(current_payload.get("data_out", "") or ""),
|
|
62
|
+
"files": str(current_payload.get("files", "*.json") or "*.json"),
|
|
63
|
+
"nfile": int(current_payload.get("nfile", 1) or 1),
|
|
64
|
+
"routing_policy": str(current_payload.get("routing_policy", "shortest_path") or "shortest_path"),
|
|
65
|
+
"sim_time_s": float(current_payload.get("sim_time_s", 30.0) or 30.0),
|
|
66
|
+
"sampling_interval_s": float(current_payload.get("sampling_interval_s", 0.5) or 0.5),
|
|
67
|
+
"source_rate_pps": float(current_payload.get("source_rate_pps", 14.0) or 14.0),
|
|
68
|
+
"queue_weight": float(current_payload.get("queue_weight", 2.5) or 2.5),
|
|
69
|
+
"random_seed": int(current_payload.get("random_seed", 2026) or 2026),
|
|
70
|
+
"reset_target": bool(current_payload.get("reset_target", False)),
|
|
71
|
+
}
|
|
72
|
+
for key, value in defaults.items():
|
|
73
|
+
st.session_state.setdefault(_k(key), value)
|
|
74
|
+
|
|
75
|
+
c1, c2, c3, c4 = st.columns([2, 2, 1.2, 1.2])
|
|
76
|
+
with c1:
|
|
77
|
+
st.text_input("Scenario directory", key=_k("data_in"))
|
|
78
|
+
with c2:
|
|
79
|
+
st.text_input("Results directory", key=_k("data_out"))
|
|
80
|
+
with c3:
|
|
81
|
+
st.text_input("Files glob", key=_k("files"))
|
|
82
|
+
with c4:
|
|
83
|
+
st.number_input("Number of files", key=_k("nfile"), min_value=1, step=1)
|
|
84
|
+
|
|
85
|
+
c5, c6, c7 = st.columns([1.5, 1.2, 1.1])
|
|
86
|
+
with c5:
|
|
87
|
+
st.selectbox("Routing policy", options=["shortest_path", "queue_aware"], key=_k("routing_policy"))
|
|
88
|
+
with c6:
|
|
89
|
+
st.number_input("Sim time (s)", key=_k("sim_time_s"), min_value=2.0, max_value=600.0, step=1.0)
|
|
90
|
+
with c7:
|
|
91
|
+
st.checkbox("Reset output", key=_k("reset_target"))
|
|
92
|
+
|
|
93
|
+
c8, c9, c10, c11 = st.columns([1.1, 1.1, 1.1, 1.1])
|
|
94
|
+
with c8:
|
|
95
|
+
st.number_input("Sampling (s)", key=_k("sampling_interval_s"), min_value=0.1, max_value=10.0, step=0.1)
|
|
96
|
+
with c9:
|
|
97
|
+
st.number_input("Source rate (pps)", key=_k("source_rate_pps"), min_value=0.1, max_value=500.0, step=0.5)
|
|
98
|
+
with c10:
|
|
99
|
+
st.number_input("Queue weight", key=_k("queue_weight"), min_value=0.0, max_value=20.0, step=0.1)
|
|
100
|
+
with c11:
|
|
101
|
+
st.number_input("Random seed", key=_k("random_seed"), min_value=0, step=1)
|
|
102
|
+
|
|
103
|
+
candidate: dict[str, Any] = {
|
|
104
|
+
"files": (st.session_state.get(_k("files")) or "*.json").strip() or "*.json",
|
|
105
|
+
"nfile": st.session_state.get(_k("nfile"), 1),
|
|
106
|
+
"routing_policy": st.session_state.get(_k("routing_policy")) or "shortest_path",
|
|
107
|
+
"sim_time_s": st.session_state.get(_k("sim_time_s"), 30.0),
|
|
108
|
+
"sampling_interval_s": st.session_state.get(_k("sampling_interval_s"), 0.5),
|
|
109
|
+
"source_rate_pps": st.session_state.get(_k("source_rate_pps"), 14.0),
|
|
110
|
+
"queue_weight": st.session_state.get(_k("queue_weight"), 2.5),
|
|
111
|
+
"random_seed": st.session_state.get(_k("random_seed"), 2026),
|
|
112
|
+
"reset_target": bool(st.session_state.get(_k("reset_target"), False)),
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
data_in_raw = (st.session_state.get(_k("data_in")) or "").strip()
|
|
116
|
+
data_out_raw = (st.session_state.get(_k("data_out")) or "").strip()
|
|
117
|
+
if data_in_raw:
|
|
118
|
+
candidate["data_in"] = data_in_raw
|
|
119
|
+
if data_out_raw:
|
|
120
|
+
candidate["data_out"] = data_out_raw
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
validated = UavRelayQueueArgs(**candidate)
|
|
124
|
+
except ValidationError as exc:
|
|
125
|
+
st.error("Invalid UAV relay queue parameters:")
|
|
126
|
+
if hasattr(env, "humanize_validation_errors"):
|
|
127
|
+
for msg in env.humanize_validation_errors(exc):
|
|
128
|
+
st.markdown(msg)
|
|
129
|
+
else:
|
|
130
|
+
st.code(str(exc))
|
|
131
|
+
else:
|
|
132
|
+
validated_payload = validated.model_dump(mode="json")
|
|
133
|
+
if validated_payload != current_payload:
|
|
134
|
+
dump_args(validated, settings_path)
|
|
135
|
+
app_settings = st.session_state.get("app_settings")
|
|
136
|
+
if not isinstance(app_settings, dict):
|
|
137
|
+
app_settings = {}
|
|
138
|
+
app_settings.setdefault("cluster", {})
|
|
139
|
+
app_settings["args"] = validated_payload
|
|
140
|
+
app_settings.setdefault("pages", {})
|
|
141
|
+
app_settings["pages"]["view_module"] = ["view_relay_resilience", "view_maps_network"]
|
|
142
|
+
st.session_state["app_settings"] = app_settings
|
|
143
|
+
st.session_state["is_args_from_ui"] = True
|
|
144
|
+
st.success(f"Saved to `{settings_path}`.")
|
|
145
|
+
else:
|
|
146
|
+
st.info("No changes to save.")
|
|
147
|
+
|
|
148
|
+
resolved_data_in = env.resolve_share_path(validated.data_in)
|
|
149
|
+
resolved_data_out = env.resolve_share_path(validated.data_out)
|
|
150
|
+
if not any(resolved_data_in.glob(validated.files)):
|
|
151
|
+
st.info("No matching scenario file exists yet. The bundled sample scenario will be seeded on first run.")
|
|
152
|
+
st.caption(
|
|
153
|
+
f"Resolved input: `{resolved_data_in}` • results: `{resolved_data_out}` • "
|
|
154
|
+
f"analysis artifacts: `{artifact_root}`"
|
|
155
|
+
)
|
|
156
|
+
st.caption(
|
|
157
|
+
"The default sample is tuned to create a queue hotspot on `relay_a` under "
|
|
158
|
+
"`shortest_path`, then improve when you switch to `queue_aware`."
|
|
159
|
+
)
|
|
160
|
+
st.caption(
|
|
161
|
+
"Each run also exports `pipeline/topology.gml`, `pipeline/allocations_steps.csv`, and "
|
|
162
|
+
"per-node trajectory CSVs so `view_maps_network` can reuse the same scenario."
|
|
163
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[args]
|
|
2
|
+
data_in = "uav_relay_queue/scenarios"
|
|
3
|
+
data_out = "uav_relay_queue/results"
|
|
4
|
+
files = "*.json"
|
|
5
|
+
nfile = 1
|
|
6
|
+
routing_policy = "shortest_path"
|
|
7
|
+
sim_time_s = 30.0
|
|
8
|
+
sampling_interval_s = 0.5
|
|
9
|
+
source_rate_pps = 14.0
|
|
10
|
+
queue_weight = 2.5
|
|
11
|
+
random_seed = 2026
|
|
12
|
+
reset_target = false
|
|
13
|
+
|
|
14
|
+
[cluster]
|
|
15
|
+
verbose = 1
|
|
16
|
+
cython = false
|
|
17
|
+
pool = false
|
|
18
|
+
rapids = false
|
|
19
|
+
cluster_enabled = false
|
|
20
|
+
scheduler = "127.0.0.1:8786"
|
|
21
|
+
workers_data_path = ""
|
|
22
|
+
|
|
23
|
+
[cluster.workers]
|
|
24
|
+
"127.0.0.1" = 2
|
|
25
|
+
|
|
26
|
+
[cluster.service_health]
|
|
27
|
+
allow_idle = false
|
|
28
|
+
max_unhealthy = 0
|
|
29
|
+
max_restart_rate = 0.25
|
|
30
|
+
|
|
31
|
+
[connector_catalog]
|
|
32
|
+
path = "connectors/data_connectors.toml"
|
|
33
|
+
|
|
34
|
+
[connector_refs]
|
|
35
|
+
scenario_sql = "uav_relay_queue_scenarios_sql"
|
|
36
|
+
operator_events = "uav_relay_queue_ops_opensearch"
|
|
37
|
+
artifact_store = "uav_relay_queue_artifact_store"
|
|
38
|
+
|
|
39
|
+
[page_connector_refs.view_relay_resilience]
|
|
40
|
+
relay_metrics = "uav_relay_queue_artifact_store"
|
|
41
|
+
operator_events = "uav_relay_queue_ops_opensearch"
|
|
42
|
+
|
|
43
|
+
[page_connector_refs.view_maps_network]
|
|
44
|
+
network_evidence = "uav_relay_queue_ops_opensearch"
|
|
45
|
+
|
|
46
|
+
[legacy_paths]
|
|
47
|
+
data_in = "uav_relay_queue/scenarios"
|
|
48
|
+
data_out = "uav_relay_queue/results"
|
|
49
|
+
|
|
50
|
+
[pages]
|
|
51
|
+
view_module = [
|
|
52
|
+
"view_relay_resilience",
|
|
53
|
+
"view_maps_network",
|
|
54
|
+
]
|