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.
- lang2sim-2.0.0/LICENSE +21 -0
- lang2sim-2.0.0/PKG-INFO +53 -0
- lang2sim-2.0.0/README.md +25 -0
- lang2sim-2.0.0/lang2sim/__init__.py +47 -0
- lang2sim-2.0.0/lang2sim/agent/__init__.py +5 -0
- lang2sim-2.0.0/lang2sim/agent/nemotron_client.py +109 -0
- lang2sim-2.0.0/lang2sim/agent/react_loop.py +848 -0
- lang2sim-2.0.0/lang2sim/agent/tools.py +998 -0
- lang2sim-2.0.0/lang2sim/cli/app.py +183 -0
- lang2sim-2.0.0/lang2sim/cli/screens/__init__.py +8 -0
- lang2sim-2.0.0/lang2sim/cli/screens/command_palette_modal.py +146 -0
- lang2sim-2.0.0/lang2sim/cli/screens/landing_screen.py +96 -0
- lang2sim-2.0.0/lang2sim/cli/screens/sessions_modal.py +236 -0
- lang2sim-2.0.0/lang2sim/cli/screens/workspace_screen.py +709 -0
- lang2sim-2.0.0/lang2sim/cli/widgets/__init__.py +16 -0
- lang2sim-2.0.0/lang2sim/cli/widgets/action_pill.py +67 -0
- lang2sim-2.0.0/lang2sim/cli/widgets/command_card.py +265 -0
- lang2sim-2.0.0/lang2sim/cli/widgets/plan_card.py +106 -0
- lang2sim-2.0.0/lang2sim/cli/widgets/prompt_card.py +96 -0
- lang2sim-2.0.0/lang2sim/cli/widgets/telemetry_sidebar.py +117 -0
- lang2sim-2.0.0/lang2sim/cli/widgets/thought_box.py +64 -0
- lang2sim-2.0.0/lang2sim/compiler/__init__.py +15 -0
- lang2sim-2.0.0/lang2sim/compiler/sdf_compiler.py +65 -0
- lang2sim-2.0.0/lang2sim/compiler/sir_generator.py +46 -0
- lang2sim-2.0.0/lang2sim/compiler/sir_validator.py +87 -0
- lang2sim-2.0.0/lang2sim/core/__init__.py +50 -0
- lang2sim-2.0.0/lang2sim/core/config.py +116 -0
- lang2sim-2.0.0/lang2sim/core/models.py +279 -0
- lang2sim-2.0.0/lang2sim/core/session_manager.py +189 -0
- lang2sim-2.0.0/lang2sim/perturbation/__init__.py +50 -0
- lang2sim-2.0.0/lang2sim/perturbation/_compat.py +19 -0
- lang2sim-2.0.0/lang2sim/perturbation/gazebo_bridge.py +520 -0
- lang2sim-2.0.0/lang2sim/perturbation/mcp_server.py +129 -0
- lang2sim-2.0.0/lang2sim/perturbation/routers/__init__.py +19 -0
- lang2sim-2.0.0/lang2sim/perturbation/routers/world.py +110 -0
- lang2sim-2.0.0/lang2sim/perturbation/sdf_snippets.py +112 -0
- lang2sim-2.0.0/lang2sim/runtime/__init__.py +7 -0
- lang2sim-2.0.0/lang2sim/runtime/control_api/__init__.py +7 -0
- lang2sim-2.0.0/lang2sim/runtime/control_api/client.py +187 -0
- lang2sim-2.0.0/lang2sim/runtime/control_api/server.py +504 -0
- lang2sim-2.0.0/lang2sim/runtime/display.py +141 -0
- lang2sim-2.0.0/lang2sim/runtime/docker_runner.py +286 -0
- lang2sim-2.0.0/lang2sim/runtime/doctor.py +220 -0
- lang2sim-2.0.0/lang2sim/runtime/hardware_probe.py +144 -0
- lang2sim-2.0.0/lang2sim/runtime/health_monitor.py +66 -0
- lang2sim-2.0.0/lang2sim/runtime/launch_builder.py +137 -0
- lang2sim-2.0.0/lang2sim/runtime/nav2_dispatcher.py +215 -0
- lang2sim-2.0.0/lang2sim/runtime/platform.py +137 -0
- lang2sim-2.0.0/lang2sim/runtime/ros_bridge.py +183 -0
- lang2sim-2.0.0/lang2sim/runtime/run_folder.py +86 -0
- lang2sim-2.0.0/lang2sim/runtime/self_healing.py +387 -0
- lang2sim-2.0.0/lang2sim/runtime/session.py +136 -0
- lang2sim-2.0.0/lang2sim/runtime/world_check.py +197 -0
- lang2sim-2.0.0/lang2sim/telemetry/__init__.py +85 -0
- lang2sim-2.0.0/lang2sim/telemetry/nqi_scorer.py +645 -0
- lang2sim-2.0.0/lang2sim/telemetry/ros_subscribers.py +489 -0
- lang2sim-2.0.0/lang2sim/telemetry/trajectory.py +258 -0
- lang2sim-2.0.0/lang2sim/telemetry/vision.py +477 -0
- lang2sim-2.0.0/lang2sim/world_gen/__init__.py +16 -0
- lang2sim-2.0.0/lang2sim/world_gen/catalog_loader.py +83 -0
- lang2sim-2.0.0/lang2sim/world_gen/map_slicer.py +131 -0
- lang2sim-2.0.0/lang2sim/world_gen/shapely_solver.py +256 -0
- lang2sim-2.0.0/lang2sim.egg-info/PKG-INFO +53 -0
- lang2sim-2.0.0/lang2sim.egg-info/SOURCES.txt +87 -0
- lang2sim-2.0.0/lang2sim.egg-info/dependency_links.txt +1 -0
- lang2sim-2.0.0/lang2sim.egg-info/entry_points.txt +2 -0
- lang2sim-2.0.0/lang2sim.egg-info/requires.txt +21 -0
- lang2sim-2.0.0/lang2sim.egg-info/top_level.txt +1 -0
- lang2sim-2.0.0/pyproject.toml +44 -0
- lang2sim-2.0.0/setup.cfg +4 -0
- lang2sim-2.0.0/tests/test_agent_tui.py +354 -0
- lang2sim-2.0.0/tests/test_catalog.py +67 -0
- lang2sim-2.0.0/tests/test_control_api.py +159 -0
- lang2sim-2.0.0/tests/test_control_api_nav.py +185 -0
- lang2sim-2.0.0/tests/test_core_models.py +175 -0
- lang2sim-2.0.0/tests/test_fixtures.py +28 -0
- lang2sim-2.0.0/tests/test_health_monitor.py +40 -0
- lang2sim-2.0.0/tests/test_launch_builder.py +58 -0
- lang2sim-2.0.0/tests/test_nav2_dispatcher.py +167 -0
- lang2sim-2.0.0/tests/test_part1_contract.py +38 -0
- lang2sim-2.0.0/tests/test_perturbation_telemetry.py +481 -0
- lang2sim-2.0.0/tests/test_react_supervisor.py +478 -0
- lang2sim-2.0.0/tests/test_ros_bridge.py +51 -0
- lang2sim-2.0.0/tests/test_run_folder.py +73 -0
- lang2sim-2.0.0/tests/test_runtime_launch.py +324 -0
- lang2sim-2.0.0/tests/test_self_healing.py +274 -0
- lang2sim-2.0.0/tests/test_session.py +76 -0
- lang2sim-2.0.0/tests/test_world_check.py +112 -0
- 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.
|
lang2sim-2.0.0/PKG-INFO
ADDED
|
@@ -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
|
+
|
lang2sim-2.0.0/README.md
ADDED
|
@@ -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,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
|
+
|