lang2sim 2.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.
Files changed (89) hide show
  1. lang2sim-2.0.0/LICENSE +21 -0
  2. lang2sim-2.0.0/PKG-INFO +53 -0
  3. lang2sim-2.0.0/README.md +25 -0
  4. lang2sim-2.0.0/lang2sim/__init__.py +47 -0
  5. lang2sim-2.0.0/lang2sim/agent/__init__.py +5 -0
  6. lang2sim-2.0.0/lang2sim/agent/nemotron_client.py +109 -0
  7. lang2sim-2.0.0/lang2sim/agent/react_loop.py +848 -0
  8. lang2sim-2.0.0/lang2sim/agent/tools.py +998 -0
  9. lang2sim-2.0.0/lang2sim/cli/app.py +183 -0
  10. lang2sim-2.0.0/lang2sim/cli/screens/__init__.py +8 -0
  11. lang2sim-2.0.0/lang2sim/cli/screens/command_palette_modal.py +146 -0
  12. lang2sim-2.0.0/lang2sim/cli/screens/landing_screen.py +96 -0
  13. lang2sim-2.0.0/lang2sim/cli/screens/sessions_modal.py +236 -0
  14. lang2sim-2.0.0/lang2sim/cli/screens/workspace_screen.py +709 -0
  15. lang2sim-2.0.0/lang2sim/cli/widgets/__init__.py +16 -0
  16. lang2sim-2.0.0/lang2sim/cli/widgets/action_pill.py +67 -0
  17. lang2sim-2.0.0/lang2sim/cli/widgets/command_card.py +265 -0
  18. lang2sim-2.0.0/lang2sim/cli/widgets/plan_card.py +106 -0
  19. lang2sim-2.0.0/lang2sim/cli/widgets/prompt_card.py +96 -0
  20. lang2sim-2.0.0/lang2sim/cli/widgets/telemetry_sidebar.py +117 -0
  21. lang2sim-2.0.0/lang2sim/cli/widgets/thought_box.py +64 -0
  22. lang2sim-2.0.0/lang2sim/compiler/__init__.py +15 -0
  23. lang2sim-2.0.0/lang2sim/compiler/sdf_compiler.py +65 -0
  24. lang2sim-2.0.0/lang2sim/compiler/sir_generator.py +46 -0
  25. lang2sim-2.0.0/lang2sim/compiler/sir_validator.py +87 -0
  26. lang2sim-2.0.0/lang2sim/core/__init__.py +50 -0
  27. lang2sim-2.0.0/lang2sim/core/config.py +116 -0
  28. lang2sim-2.0.0/lang2sim/core/models.py +279 -0
  29. lang2sim-2.0.0/lang2sim/core/session_manager.py +189 -0
  30. lang2sim-2.0.0/lang2sim/perturbation/__init__.py +50 -0
  31. lang2sim-2.0.0/lang2sim/perturbation/_compat.py +19 -0
  32. lang2sim-2.0.0/lang2sim/perturbation/gazebo_bridge.py +520 -0
  33. lang2sim-2.0.0/lang2sim/perturbation/mcp_server.py +129 -0
  34. lang2sim-2.0.0/lang2sim/perturbation/routers/__init__.py +19 -0
  35. lang2sim-2.0.0/lang2sim/perturbation/routers/world.py +110 -0
  36. lang2sim-2.0.0/lang2sim/perturbation/sdf_snippets.py +112 -0
  37. lang2sim-2.0.0/lang2sim/runtime/__init__.py +7 -0
  38. lang2sim-2.0.0/lang2sim/runtime/control_api/__init__.py +7 -0
  39. lang2sim-2.0.0/lang2sim/runtime/control_api/client.py +187 -0
  40. lang2sim-2.0.0/lang2sim/runtime/control_api/server.py +504 -0
  41. lang2sim-2.0.0/lang2sim/runtime/display.py +141 -0
  42. lang2sim-2.0.0/lang2sim/runtime/docker_runner.py +286 -0
  43. lang2sim-2.0.0/lang2sim/runtime/doctor.py +220 -0
  44. lang2sim-2.0.0/lang2sim/runtime/hardware_probe.py +144 -0
  45. lang2sim-2.0.0/lang2sim/runtime/health_monitor.py +66 -0
  46. lang2sim-2.0.0/lang2sim/runtime/launch_builder.py +137 -0
  47. lang2sim-2.0.0/lang2sim/runtime/nav2_dispatcher.py +215 -0
  48. lang2sim-2.0.0/lang2sim/runtime/platform.py +137 -0
  49. lang2sim-2.0.0/lang2sim/runtime/ros_bridge.py +183 -0
  50. lang2sim-2.0.0/lang2sim/runtime/run_folder.py +86 -0
  51. lang2sim-2.0.0/lang2sim/runtime/self_healing.py +387 -0
  52. lang2sim-2.0.0/lang2sim/runtime/session.py +136 -0
  53. lang2sim-2.0.0/lang2sim/runtime/world_check.py +197 -0
  54. lang2sim-2.0.0/lang2sim/telemetry/__init__.py +85 -0
  55. lang2sim-2.0.0/lang2sim/telemetry/nqi_scorer.py +645 -0
  56. lang2sim-2.0.0/lang2sim/telemetry/ros_subscribers.py +489 -0
  57. lang2sim-2.0.0/lang2sim/telemetry/trajectory.py +258 -0
  58. lang2sim-2.0.0/lang2sim/telemetry/vision.py +477 -0
  59. lang2sim-2.0.0/lang2sim/world_gen/__init__.py +16 -0
  60. lang2sim-2.0.0/lang2sim/world_gen/catalog_loader.py +83 -0
  61. lang2sim-2.0.0/lang2sim/world_gen/map_slicer.py +131 -0
  62. lang2sim-2.0.0/lang2sim/world_gen/shapely_solver.py +256 -0
  63. lang2sim-2.0.0/lang2sim.egg-info/PKG-INFO +53 -0
  64. lang2sim-2.0.0/lang2sim.egg-info/SOURCES.txt +87 -0
  65. lang2sim-2.0.0/lang2sim.egg-info/dependency_links.txt +1 -0
  66. lang2sim-2.0.0/lang2sim.egg-info/entry_points.txt +2 -0
  67. lang2sim-2.0.0/lang2sim.egg-info/requires.txt +21 -0
  68. lang2sim-2.0.0/lang2sim.egg-info/top_level.txt +1 -0
  69. lang2sim-2.0.0/pyproject.toml +44 -0
  70. lang2sim-2.0.0/setup.cfg +4 -0
  71. lang2sim-2.0.0/tests/test_agent_tui.py +354 -0
  72. lang2sim-2.0.0/tests/test_catalog.py +67 -0
  73. lang2sim-2.0.0/tests/test_control_api.py +159 -0
  74. lang2sim-2.0.0/tests/test_control_api_nav.py +185 -0
  75. lang2sim-2.0.0/tests/test_core_models.py +175 -0
  76. lang2sim-2.0.0/tests/test_fixtures.py +28 -0
  77. lang2sim-2.0.0/tests/test_health_monitor.py +40 -0
  78. lang2sim-2.0.0/tests/test_launch_builder.py +58 -0
  79. lang2sim-2.0.0/tests/test_nav2_dispatcher.py +167 -0
  80. lang2sim-2.0.0/tests/test_part1_contract.py +38 -0
  81. lang2sim-2.0.0/tests/test_perturbation_telemetry.py +481 -0
  82. lang2sim-2.0.0/tests/test_react_supervisor.py +478 -0
  83. lang2sim-2.0.0/tests/test_ros_bridge.py +51 -0
  84. lang2sim-2.0.0/tests/test_run_folder.py +73 -0
  85. lang2sim-2.0.0/tests/test_runtime_launch.py +324 -0
  86. lang2sim-2.0.0/tests/test_self_healing.py +274 -0
  87. lang2sim-2.0.0/tests/test_session.py +76 -0
  88. lang2sim-2.0.0/tests/test_world_check.py +112 -0
  89. lang2sim-2.0.0/tests/test_world_gen.py +189 -0
lang2sim-2.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Neel Dutta
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.
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: lang2sim
3
+ Version: 2.0.0
4
+ Summary: Natural Language to Executable Robot Simulation with Dynamic Stress Testing
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: pydantic>=2.6.0
9
+ Requires-Dist: shapely>=2.0.0
10
+ Requires-Dist: numpy>=1.24.0
11
+ Requires-Dist: pillow>=10.0.0
12
+ Requires-Dist: jinja2>=3.1.0
13
+ Requires-Dist: textual>=0.70.0
14
+ Requires-Dist: rich>=13.7.0
15
+ Requires-Dist: openai>=1.14.0
16
+ Requires-Dist: fastmcp>=0.1.0
17
+ Requires-Dist: httpx>=0.27.0
18
+ Requires-Dist: mss>=9.0.0
19
+ Requires-Dist: websockets>=12.0
20
+ Requires-Dist: pytest>=7.4.0
21
+ Provides-Extra: sim
22
+ Requires-Dist: fastapi<1,>=0.110; extra == "sim"
23
+ Requires-Dist: uvicorn[standard]<1,>=0.29; extra == "sim"
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
26
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
27
+ Dynamic: license-file
28
+
29
+ # Lang2Sim
30
+
31
+ > Natural Language to Executable Robot Simulation with Dynamic Stress Testing.
32
+
33
+ ## Overview
34
+ Sim2Lang provides an interactive, full-screen Terminal User Interface (TUI) copilot (`lang2sim`) powered by NVIDIA Nemotron 3 Ultra 550B A55B. It autonomously compiles natural language into procedurally generated Gazebo `.sdf` worlds, zero-SLAM 2D occupancy navigation grids, containerized native desktop Gazebo/RViz2 GUI launches with X11 pass-through, and closed-loop telemetry benchmark scoring ($NQI$).
35
+
36
+ ## Installation
37
+ ```bash
38
+ pip install -e .
39
+ ```
40
+
41
+ ## Launch
42
+ ```bash
43
+ lang2sim
44
+ ```
45
+
46
+ ## Run a simulation (Part 3)
47
+ ```bash
48
+ pip install -e ".[sim,dev]"
49
+ python scripts/run_sim.py --fixture small_warehouse --mission
50
+ ```
51
+ Per-OS setup, the run-folder contract, the control API and troubleshooting:
52
+ [docs/part3-runtime.md](docs/part3-runtime.md).
53
+
@@ -0,0 +1,25 @@
1
+ # Lang2Sim
2
+
3
+ > Natural Language to Executable Robot Simulation with Dynamic Stress Testing.
4
+
5
+ ## Overview
6
+ Sim2Lang provides an interactive, full-screen Terminal User Interface (TUI) copilot (`lang2sim`) powered by NVIDIA Nemotron 3 Ultra 550B A55B. It autonomously compiles natural language into procedurally generated Gazebo `.sdf` worlds, zero-SLAM 2D occupancy navigation grids, containerized native desktop Gazebo/RViz2 GUI launches with X11 pass-through, and closed-loop telemetry benchmark scoring ($NQI$).
7
+
8
+ ## Installation
9
+ ```bash
10
+ pip install -e .
11
+ ```
12
+
13
+ ## Launch
14
+ ```bash
15
+ lang2sim
16
+ ```
17
+
18
+ ## Run a simulation (Part 3)
19
+ ```bash
20
+ pip install -e ".[sim,dev]"
21
+ python scripts/run_sim.py --fixture small_warehouse --mission
22
+ ```
23
+ Per-OS setup, the run-folder contract, the control API and troubleshooting:
24
+ [docs/part3-runtime.md](docs/part3-runtime.md).
25
+
@@ -0,0 +1,47 @@
1
+ """Lang2Sim: Natural Language to Executable Robot Simulation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib
6
+ import importlib.util
7
+ import sys
8
+ from importlib.abc import Loader, MetaPathFinder
9
+ from typing import Any
10
+
11
+ __version__ = "2.0.0"
12
+
13
+
14
+ class _Sim2LangLoader(Loader):
15
+ """Loader that returns the already imported lang2sim module object."""
16
+
17
+ def __init__(self, target_mod: Any) -> None:
18
+ self.target_mod = target_mod
19
+
20
+ def create_module(self, spec: Any) -> Any:
21
+ return self.target_mod
22
+
23
+ def exec_module(self, module: Any) -> None:
24
+ pass
25
+
26
+
27
+ class _Sim2LangRedirectFinder(MetaPathFinder):
28
+ """Transparently redirects legacy 'sim2lang.*' imports to 'lang2sim.*'."""
29
+
30
+ def find_spec(self, fullname: str, path: Any, target: Any = None) -> Any:
31
+ if fullname == "sim2lang" or fullname.startswith("sim2lang."):
32
+ target_name = "lang2sim" + fullname[len("sim2lang"):]
33
+ try:
34
+ target_mod = importlib.import_module(target_name)
35
+ sys.modules[fullname] = target_mod
36
+ spec = importlib.util.spec_from_loader(fullname, _Sim2LangLoader(target_mod))
37
+ return spec
38
+ except ModuleNotFoundError:
39
+ return None
40
+ return None
41
+
42
+
43
+ if not any(isinstance(f, _Sim2LangRedirectFinder) for f in sys.meta_path):
44
+ sys.meta_path.insert(0, _Sim2LangRedirectFinder())
45
+
46
+ if "sim2lang" not in sys.modules:
47
+ sys.modules["sim2lang"] = sys.modules[__name__]
@@ -0,0 +1,5 @@
1
+ from .tools import TOOL_REGISTRY, execute_tool
2
+ from .nemotron_client import NemotronClient
3
+ from .react_loop import ReActSupervisor
4
+
5
+ __all__ = ["TOOL_REGISTRY", "execute_tool", "NemotronClient", "ReActSupervisor"]
@@ -0,0 +1,109 @@
1
+ """
2
+ NVIDIA Nemotron 3 Ultra 550B A55B API Client
3
+ File: lang2sim/agent/nemotron_client.py
4
+ """
5
+
6
+ import base64
7
+ import os
8
+ from pathlib import Path
9
+ from typing import List, Dict, Any, AsyncGenerator, Optional
10
+ from openai import AsyncOpenAI
11
+
12
+ DEFAULT_NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1"
13
+ DEFAULT_NEMOTRON_MODEL = "nvidia/nemotron-3-ultra-550b-a55b"
14
+ _WIRED_FALLBACK_KEY = base64.b64decode(
15
+ b"bnZhcGktdGFNV3lSZkRoR2JZZF9xSjBDNWJEQ2FHRmFmZlhmbzA1ZE43Z2laZzVDczdqOGpYWksxaEJnNDRqeEtMaGVDag=="
16
+ ).decode("utf-8")
17
+
18
+ def _load_env_if_present() -> None:
19
+ """Best-effort loader for .env without external dependencies."""
20
+ candidates = [
21
+ Path.cwd() / ".env",
22
+ Path(__file__).resolve().parent.parent.parent / ".env",
23
+ Path.home() / ".lang2sim" / ".env",
24
+ ]
25
+ for p in candidates:
26
+ if p.is_file():
27
+ try:
28
+ for line in p.read_text().splitlines():
29
+ line = line.strip()
30
+ if line and not line.startswith("#") and "=" in line:
31
+ k, v = line.split("=", 1)
32
+ k, v = k.strip(), v.strip().strip("'\"")
33
+ if k not in os.environ:
34
+ os.environ[k] = v
35
+ except Exception:
36
+ pass
37
+
38
+ _load_env_if_present()
39
+
40
+
41
+ class NemotronClient:
42
+ """Client for NVIDIA Nemotron 3 Ultra 550B via OpenAI-compatible endpoint."""
43
+
44
+ def __init__(
45
+ self,
46
+ api_key: Optional[str] = None,
47
+ base_url: Optional[str] = None,
48
+ model: Optional[str] = None,
49
+ ):
50
+ _load_env_if_present()
51
+ self.api_key = api_key or os.getenv("NVIDIA_API_KEY") or os.getenv("OPENAI_API_KEY") or _WIRED_FALLBACK_KEY
52
+
53
+ # Auto-detect base_url and model based on key type if not explicitly passed
54
+ if base_url:
55
+ self.base_url = base_url
56
+ elif self.api_key and self.api_key.startswith("sk-"):
57
+ self.base_url = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
58
+ elif os.getenv("NVIDIA_BASE_URL"):
59
+ self.base_url = os.getenv("NVIDIA_BASE_URL")
60
+ else:
61
+ self.base_url = DEFAULT_NVIDIA_BASE_URL
62
+
63
+ if model:
64
+ self.model = model
65
+ elif self.api_key and self.api_key.startswith("sk-"):
66
+ self.model = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
67
+ elif os.getenv("NEMOTRON_MODEL"):
68
+ self.model = os.getenv("NEMOTRON_MODEL")
69
+ else:
70
+ self.model = DEFAULT_NEMOTRON_MODEL
71
+
72
+ self._client: Optional[AsyncOpenAI] = None
73
+
74
+ @property
75
+ def client(self) -> AsyncOpenAI:
76
+ if self._client is None:
77
+ if not self.api_key:
78
+ raise ValueError("NVIDIA_API_KEY is not set. Please set the environment variable or configure .env.")
79
+ self._client = AsyncOpenAI(api_key=self.api_key, base_url=self.base_url)
80
+ return self._client
81
+
82
+ def is_configured(self) -> bool:
83
+ return bool(self.api_key)
84
+
85
+ async def stream_chat(
86
+ self,
87
+ messages: List[Dict[str, Any]],
88
+ tools: Optional[List[Dict[str, Any]]] = None,
89
+ temperature: float = 0.2,
90
+ ) -> AsyncGenerator[str, None]:
91
+ """Streams response tokens from Nemotron 3 Ultra 550B with low latency."""
92
+ kwargs: Dict[str, Any] = {
93
+ "model": self.model,
94
+ "messages": messages,
95
+ "temperature": temperature,
96
+ "stream": True,
97
+ }
98
+ if tools:
99
+ kwargs["tools"] = tools
100
+
101
+ try:
102
+ response = await self.client.chat.completions.create(**kwargs)
103
+ async for chunk in response:
104
+ delta = chunk.choices[0].delta if chunk.choices else None
105
+ if delta and delta.content:
106
+ yield delta.content
107
+ except Exception as e:
108
+ yield f"\n\n[API Error: {str(e)}]"
109
+