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.
Files changed (34) hide show
  1. agi_app_uav_relay_queue-0.1.0/LICENSE +22 -0
  2. agi_app_uav_relay_queue-0.1.0/PKG-INFO +49 -0
  3. agi_app_uav_relay_queue-0.1.0/README.md +19 -0
  4. agi_app_uav_relay_queue-0.1.0/pyproject.toml +84 -0
  5. agi_app_uav_relay_queue-0.1.0/setup.cfg +4 -0
  6. agi_app_uav_relay_queue-0.1.0/setup.py +47 -0
  7. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/__init__.py +33 -0
  8. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/README.md +64 -0
  9. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/lab_stages.toml +4 -0
  10. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/notebook_export.toml +26 -0
  11. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/pipeline_view.dot +13 -0
  12. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/pyproject.toml +13 -0
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue/project/uav_relay_queue_project/uv_config.toml +5 -0
  29. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/PKG-INFO +49 -0
  30. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/SOURCES.txt +11 -0
  31. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/dependency_links.txt +1 -0
  32. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/entry_points.txt +3 -0
  33. agi_app_uav_relay_queue-0.1.0/src/agi_app_uav_relay_queue.egg-info/requires.txt +1 -0
  34. 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
+ [![PyPI version](https://img.shields.io/pypi/v/agi-app-uav-relay-queue.svg?cacheSeconds=300)](https://pypi.org/project/agi-app-uav-relay-queue/)
34
+ [![Python versions](https://img.shields.io/pypi/pyversions/agi-app-uav-relay-queue.svg)](https://pypi.org/project/agi-app-uav-relay-queue/)
35
+ [![License: BSD 3-Clause](https://img.shields.io/pypi/l/agi-app-uav-relay-queue)](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
+ [![PyPI version](https://img.shields.io/pypi/v/agi-app-uav-relay-queue.svg?cacheSeconds=300)](https://pypi.org/project/agi-app-uav-relay-queue/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/agi-app-uav-relay-queue.svg)](https://pypi.org/project/agi-app-uav-relay-queue/)
5
+ [![License: BSD 3-Clause](https://img.shields.io/pypi/l/agi-app-uav-relay-queue)](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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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"]
@@ -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
+ ]