pyterrainMap 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyterrainmap-1.0.0/.gitignore +76 -0
- pyterrainmap-1.0.0/AI_INTEGRATION.md +488 -0
- pyterrainmap-1.0.0/ARCHITECTURE.md +547 -0
- pyterrainmap-1.0.0/ARCHITECTURE_BOUNDARIES.md +437 -0
- pyterrainmap-1.0.0/ARCHITECTURE_COMPLETE_WEEK19.md +502 -0
- pyterrainmap-1.0.0/BANDWIDTH_OPTIMIZATION.md +526 -0
- pyterrainmap-1.0.0/Cargo.lock +3552 -0
- pyterrainmap-1.0.0/Cargo.toml +87 -0
- pyterrainmap-1.0.0/DATA_INTEGRITY.md +815 -0
- pyterrainmap-1.0.0/DOCUMENTATION_INDEX.md +254 -0
- pyterrainmap-1.0.0/GETTING_STARTED.md +803 -0
- pyterrainmap-1.0.0/IMPLEMENTATION_ROADMAP.md +670 -0
- pyterrainmap-1.0.0/INSTALLATION.md +388 -0
- pyterrainmap-1.0.0/LAYERED_CACHING_ARCHITECTURE.md +636 -0
- pyterrainmap-1.0.0/LICENSE +21 -0
- pyterrainmap-1.0.0/OSS_POLICY.md +350 -0
- pyterrainmap-1.0.0/PARALLEL_INFERENCE_ARCHITECTURE.md +726 -0
- pyterrainmap-1.0.0/PKG-INFO +459 -0
- pyterrainmap-1.0.0/PREDICTIVE_CACHING_ARCHITECTURE.md +647 -0
- pyterrainmap-1.0.0/PRODUCTION_STORAGE_ARCHITECTURE.md +1195 -0
- pyterrainmap-1.0.0/PYPROJECT_SETUP.md +248 -0
- pyterrainmap-1.0.0/PYTHON_BINDINGS.md +402 -0
- pyterrainmap-1.0.0/README.md +407 -0
- pyterrainmap-1.0.0/READY_TO_BUILD.md +239 -0
- pyterrainmap-1.0.0/REPRESENTATION_TYPE_SYSTEM.md +647 -0
- pyterrainmap-1.0.0/ROS_BRIDGE_ARCHITECTURE.md +437 -0
- pyterrainmap-1.0.0/ROS_BRIDGE_DELIVERY.md +417 -0
- pyterrainmap-1.0.0/ROS_BRIDGE_IMPLEMENTATION_COMPLETE.md +562 -0
- pyterrainmap-1.0.0/ROS_MOVEIT_INTEGRATION.md +723 -0
- pyterrainmap-1.0.0/SECURITY_AUDITABILITY_ARCHITECTURE.md +946 -0
- pyterrainmap-1.0.0/SESSION_WEEK19_COMPLETE.md +344 -0
- pyterrainmap-1.0.0/SIMULATION_INTEGRATION.md +662 -0
- pyterrainmap-1.0.0/TEMPORAL_NORMALIZATION.md +371 -0
- pyterrainmap-1.0.0/UNIVERSAL_ROBOT_INTEROPERABILITY.md +744 -0
- pyterrainmap-1.0.0/VISION.md +352 -0
- pyterrainmap-1.0.0/WEEK19_SUMMARY.md +310 -0
- pyterrainmap-1.0.0/pyproject.toml +140 -0
- pyterrainmap-1.0.0/pyterrainmap/okf_sensor_profiles.py +70 -0
- pyterrainmap-1.0.0/python/examples/basic_analysis.py +23 -0
- pyterrainmap-1.0.0/python/pyterrain_map/__init__.py +83 -0
- pyterrainmap-1.0.0/python/pyterrain_map/api.py +285 -0
- pyterrainmap-1.0.0/python/pyterrain_map/cli.py +131 -0
- pyterrainmap-1.0.0/python/pyterrain_map/setup_wizard.py +467 -0
- pyterrainmap-1.0.0/python/pyterrain_map/statguardian_integration.py +329 -0
- pyterrainmap-1.0.0/python/pyterrain_map/storage/__init__.py +21 -0
- pyterrainmap-1.0.0/python/pyterrain_map/storage/adls.py +319 -0
- pyterrainmap-1.0.0/python/pyterrain_map/storage/base.py +260 -0
- pyterrainmap-1.0.0/python/pyterrain_map/storage/gcs.py +271 -0
- pyterrainmap-1.0.0/python/pyterrain_map/storage/local.py +249 -0
- pyterrainmap-1.0.0/python/pyterrain_map/storage/s3.py +287 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/__init__.py +14 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/adapters/__init__.py +11 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/adapters/base.py +98 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/adapters/lidar.py +230 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/adapters/thermal.py +201 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/platforms/__init__.py +228 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/transforms/__init__.py +14 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/transforms/coordinate_frames.py +310 -0
- pyterrainmap-1.0.0/python/pyterrain_ros/transforms/tf_listener.py +331 -0
- pyterrainmap-1.0.0/quality_contracts/multi_sensor_consistency.yaml +68 -0
- pyterrainmap-1.0.0/quality_contracts/sensor_calibration.yaml +74 -0
- pyterrainmap-1.0.0/quality_contracts/temporal_coordinates.yaml +74 -0
- pyterrainmap-1.0.0/quality_contracts/terrain_anomalies.yaml +80 -0
- pyterrainmap-1.0.0/src/anomaly/mod.rs +578 -0
- pyterrainmap-1.0.0/src/api/mod.rs +614 -0
- pyterrainmap-1.0.0/src/api_tls/mod.rs +421 -0
- pyterrainmap-1.0.0/src/caching/mod.rs +618 -0
- pyterrainmap-1.0.0/src/cesium_integration/mod.rs +825 -0
- pyterrainmap-1.0.0/src/change_detection/mod.rs +668 -0
- pyterrainmap-1.0.0/src/cli/mod.rs +573 -0
- pyterrainmap-1.0.0/src/data_sources/mod.rs +568 -0
- pyterrainmap-1.0.0/src/export/mod.rs +636 -0
- pyterrainmap-1.0.0/src/export_security/mod.rs +500 -0
- pyterrainmap-1.0.0/src/fusion/mod.rs +624 -0
- pyterrainmap-1.0.0/src/intelligence/mod.rs +775 -0
- pyterrainmap-1.0.0/src/lib.rs +213 -0
- pyterrainmap-1.0.0/src/parallel_execution/mod.rs +443 -0
- pyterrainmap-1.0.0/src/persistence/mod.rs +674 -0
- pyterrainmap-1.0.0/src/photogrammetry/mod.rs +684 -0
- pyterrainmap-1.0.0/src/predictive_caching/mod.rs +799 -0
- pyterrainmap-1.0.0/src/py.rs +56 -0
- pyterrainmap-1.0.0/src/py_api.rs +394 -0
- pyterrainmap-1.0.0/src/query/mod.rs +360 -0
- pyterrainmap-1.0.0/src/reconstruction_3d/mod.rs +551 -0
- pyterrainmap-1.0.0/src/reference_images/mod.rs +527 -0
- pyterrainmap-1.0.0/src/security/mod.rs +534 -0
- pyterrainmap-1.0.0/src/slam/mod.rs +520 -0
- pyterrainmap-1.0.0/src/spatial/mod.rs +310 -0
- pyterrainmap-1.0.0/src/spatial_reasoning/mod.rs +525 -0
- pyterrainmap-1.0.0/src/storage/backends.rs +463 -0
- pyterrainmap-1.0.0/src/storage/federation.rs +257 -0
- pyterrainmap-1.0.0/src/storage/mod.rs +332 -0
- pyterrainmap-1.0.0/src/storage/postgres.rs +355 -0
- pyterrainmap-1.0.0/src/temporal/mod.rs +351 -0
- pyterrainmap-1.0.0/src/tiles_3d/mod.rs +589 -0
- pyterrainmap-1.0.0/src/types.rs +609 -0
- pyterrainmap-1.0.0/src/weather_soil/mod.rs +807 -0
- pyterrainmap-1.0.0/tests/test_statguardian_integration.py +365 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Rust
|
|
2
|
+
target/
|
|
3
|
+
Cargo.lock
|
|
4
|
+
**/*.rs.bk
|
|
5
|
+
*.pdb
|
|
6
|
+
|
|
7
|
+
# Python
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.py[cod]
|
|
10
|
+
*$py.class
|
|
11
|
+
*.so
|
|
12
|
+
.Python
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
downloads/
|
|
17
|
+
eggs/
|
|
18
|
+
.eggs/
|
|
19
|
+
lib/
|
|
20
|
+
lib64/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
pip-wheel-metadata/
|
|
26
|
+
share/python-wheels/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
.installed.cfg
|
|
29
|
+
*.egg
|
|
30
|
+
|
|
31
|
+
# Virtual environments
|
|
32
|
+
venv/
|
|
33
|
+
ENV/
|
|
34
|
+
env/
|
|
35
|
+
.venv
|
|
36
|
+
|
|
37
|
+
# IDEs
|
|
38
|
+
.vscode/
|
|
39
|
+
.idea/
|
|
40
|
+
*.swp
|
|
41
|
+
*.swo
|
|
42
|
+
*~
|
|
43
|
+
.DS_Store
|
|
44
|
+
|
|
45
|
+
# Project-specific
|
|
46
|
+
data/
|
|
47
|
+
output/
|
|
48
|
+
*.log
|
|
49
|
+
.env
|
|
50
|
+
.env.local
|
|
51
|
+
config.local.yaml
|
|
52
|
+
|
|
53
|
+
# Test coverage
|
|
54
|
+
.coverage
|
|
55
|
+
htmlcov/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
.tox/
|
|
58
|
+
|
|
59
|
+
# Build artifacts
|
|
60
|
+
*.o
|
|
61
|
+
*.a
|
|
62
|
+
*.dylib
|
|
63
|
+
*.dll
|
|
64
|
+
*.so
|
|
65
|
+
|
|
66
|
+
# Database
|
|
67
|
+
*.db
|
|
68
|
+
*.sqlite
|
|
69
|
+
*.sqlite3
|
|
70
|
+
|
|
71
|
+
# Images/cache
|
|
72
|
+
*.jpg
|
|
73
|
+
*.png
|
|
74
|
+
*.tif
|
|
75
|
+
*.tiff
|
|
76
|
+
cache/
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
# AI Integration Design
|
|
2
|
+
|
|
3
|
+
## Core Principle
|
|
4
|
+
|
|
5
|
+
PyTerrain (PyTerrainMap + PyTerrainAI) is designed to work seamlessly with **both humans and AI systems**:
|
|
6
|
+
|
|
7
|
+
- **Human programmers:** Import as regular Python library, call directly
|
|
8
|
+
- **AI code generators:** Claude Code, Copilot, Codex can generate integration code
|
|
9
|
+
- **Scripts/Bots:** Call via HTTP API or direct library import
|
|
10
|
+
- **Interactive exploration:** Use in Jupyter, REPL, Claude Code notebooks
|
|
11
|
+
|
|
12
|
+
Type hints, documentation, and examples serve both humans and AI equally well.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Design for AI Code Generation
|
|
17
|
+
|
|
18
|
+
### 1. Type Hints Everywhere
|
|
19
|
+
|
|
20
|
+
AI needs clear type information to generate correct code.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
# ✅ GOOD: AI knows exactly what to pass and what to expect
|
|
24
|
+
async def get_context(
|
|
25
|
+
bot_id: str,
|
|
26
|
+
mission: Mission,
|
|
27
|
+
location: GeoPoint,
|
|
28
|
+
radius_m: float = 50.0,
|
|
29
|
+
) -> Context:
|
|
30
|
+
"""Get mission-aligned context for bot"""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
# ❌ BAD: AI might guess wrong
|
|
34
|
+
async def get_context(bot_id, mission, location, radius=50):
|
|
35
|
+
"""Get context"""
|
|
36
|
+
...
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Clear, Parseable Docstrings
|
|
40
|
+
|
|
41
|
+
AI extracts meaning from docstrings.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
async def get_context(
|
|
45
|
+
bot_id: str,
|
|
46
|
+
mission: Mission,
|
|
47
|
+
location: GeoPoint,
|
|
48
|
+
radius_m: float = 50.0,
|
|
49
|
+
) -> Context:
|
|
50
|
+
"""
|
|
51
|
+
Get mission-aligned, temporal-decayed context for a bot.
|
|
52
|
+
|
|
53
|
+
This method:
|
|
54
|
+
1. Checks bot permissions for mission
|
|
55
|
+
2. Queries PyTerrainMap for observations
|
|
56
|
+
3. Applies temporal decay
|
|
57
|
+
4. Filters by mission (RBAC)
|
|
58
|
+
5. Detects anomalies
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
bot_id: Unique bot identifier
|
|
62
|
+
mission: Mission type (security, inspection, monitoring, maintenance)
|
|
63
|
+
location: Target location (lat, lon)
|
|
64
|
+
radius_m: Query radius in meters (default 50)
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Context object with:
|
|
68
|
+
- observations: List of filtered, decayed observations
|
|
69
|
+
- anomalies: List of flagged anomalies
|
|
70
|
+
- suggested_actions: Recommended next steps
|
|
71
|
+
- timestamp: Query execution time
|
|
72
|
+
|
|
73
|
+
Raises:
|
|
74
|
+
PermissionError: If bot not authorized for mission at location
|
|
75
|
+
ValueError: If mission type invalid
|
|
76
|
+
|
|
77
|
+
Example:
|
|
78
|
+
context = await ai.get_context(
|
|
79
|
+
bot_id="security_1",
|
|
80
|
+
mission=Mission.SECURITY,
|
|
81
|
+
location=GeoPoint(40.123, -74.567)
|
|
82
|
+
)
|
|
83
|
+
print(f"Threats: {context.anomalies}")
|
|
84
|
+
"""
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. Predictable, Deterministic APIs
|
|
88
|
+
|
|
89
|
+
AI needs to predict outcomes. No hidden state or side effects.
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# ✅ GOOD: Pure function, predictable
|
|
93
|
+
def compute_z_score(value: float, mean: float, std: float) -> float:
|
|
94
|
+
"""Compute z-score relative to mean/std"""
|
|
95
|
+
return abs(value - mean) / (std + 1e-6)
|
|
96
|
+
|
|
97
|
+
# ❌ BAD: Hidden state, unpredictable
|
|
98
|
+
def compute_z_score(value):
|
|
99
|
+
return abs(value - self.baseline.mean) / self.baseline.std # Depends on mutable state
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 4. Rich Examples
|
|
103
|
+
|
|
104
|
+
AI learns by pattern matching. Provide examples for every major flow.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
# examples/security_patrol.py
|
|
108
|
+
async def security_patrol():
|
|
109
|
+
"""Example: Security bot conducting patrol"""
|
|
110
|
+
|
|
111
|
+
map_service = PyTerrainMap()
|
|
112
|
+
ai_service = PyTerrainAI(map_service)
|
|
113
|
+
|
|
114
|
+
# Scenario: Security bot exploring Building_A
|
|
115
|
+
bot_id = "security_1"
|
|
116
|
+
building_location = GeoPoint(40.123, -74.567)
|
|
117
|
+
|
|
118
|
+
# Step 1: Plan phase (aerial view)
|
|
119
|
+
context = await ai_service.get_context(
|
|
120
|
+
bot_id=bot_id,
|
|
121
|
+
mission=Mission.SECURITY,
|
|
122
|
+
location=building_location,
|
|
123
|
+
radius_m=100,
|
|
124
|
+
detail_level=DetailLevel.AERIAL
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Step 2: Move toward anomalies
|
|
128
|
+
for anomaly in context.anomalies:
|
|
129
|
+
print(f"Investigating {anomaly.description} at {anomaly.location}")
|
|
130
|
+
|
|
131
|
+
# Step 3: Arrive and query detailed view
|
|
132
|
+
detailed = await ai_service.get_context(
|
|
133
|
+
bot_id=bot_id,
|
|
134
|
+
mission=Mission.SECURITY,
|
|
135
|
+
location=anomaly.location,
|
|
136
|
+
detail_level=DetailLevel.DETAILED
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Step 4: Report findings
|
|
140
|
+
await map_service.push_observation(Observation(
|
|
141
|
+
robot_id=bot_id,
|
|
142
|
+
location=anomaly.location,
|
|
143
|
+
sensor_type=SensorType.Camera,
|
|
144
|
+
value={"findings": "building_secure"},
|
|
145
|
+
confidence=0.95
|
|
146
|
+
))
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## API Design for AI Consumption
|
|
152
|
+
|
|
153
|
+
### HTTP REST API (For Agents, Scripts)
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
POST /context
|
|
157
|
+
{
|
|
158
|
+
"bot_id": "security_1",
|
|
159
|
+
"mission": "security",
|
|
160
|
+
"location": {"lat": 40.123, "lon": -74.567},
|
|
161
|
+
"radius_m": 50.0,
|
|
162
|
+
"detail_level": "regional"
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
Response:
|
|
166
|
+
{
|
|
167
|
+
"timestamp": 1234567890,
|
|
168
|
+
"observations": [
|
|
169
|
+
{
|
|
170
|
+
"sensor_type": "camera",
|
|
171
|
+
"value": {...},
|
|
172
|
+
"confidence": 0.95,
|
|
173
|
+
"temporal_weight": 0.85,
|
|
174
|
+
"status": "verified"
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"anomalies": [
|
|
178
|
+
{
|
|
179
|
+
"type": "temperature_spike",
|
|
180
|
+
"severity": "high",
|
|
181
|
+
"location": {"lat": 40.124, "lon": -74.568}
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
"suggested_actions": [
|
|
185
|
+
"Investigate thermal anomaly at (40.124, -74.568)",
|
|
186
|
+
"Check obstacle at (40.122, -74.566)"
|
|
187
|
+
]
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Python API (For Direct Integration)
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from pyterrain_ai import PyTerrainAI, Mission, DetailLevel
|
|
195
|
+
from pyterrain_map import PyTerrainMap, Observation, SensorType, GeoPoint
|
|
196
|
+
|
|
197
|
+
async def my_autonomous_system():
|
|
198
|
+
"""AI system using PyTerrain"""
|
|
199
|
+
|
|
200
|
+
map_svc = PyTerrainMap()
|
|
201
|
+
ai_svc = PyTerrainAI(map_svc)
|
|
202
|
+
|
|
203
|
+
# AI queries map to understand environment
|
|
204
|
+
context = await ai_svc.get_context(
|
|
205
|
+
bot_id="my_bot",
|
|
206
|
+
mission=Mission.INSPECTION,
|
|
207
|
+
location=GeoPoint(40.123, -74.567),
|
|
208
|
+
detail_level=DetailLevel.REGIONAL
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# AI processes context and makes decisions
|
|
212
|
+
if any(a.severity == "high" for a in context.anomalies):
|
|
213
|
+
print("Found critical issues!")
|
|
214
|
+
|
|
215
|
+
# AI reports findings
|
|
216
|
+
await map_svc.push_observation(Observation(
|
|
217
|
+
robot_id="my_bot",
|
|
218
|
+
location=GeoPoint(40.123, -74.567),
|
|
219
|
+
sensor_type=SensorType.Camera,
|
|
220
|
+
value={"observation": "damage_found"},
|
|
221
|
+
confidence=0.92
|
|
222
|
+
))
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### OpenAPI Schema (For AI Agents)
|
|
226
|
+
|
|
227
|
+
Auto-generate OpenAPI from Python type hints. Claude Code can read and follow schema.
|
|
228
|
+
|
|
229
|
+
```yaml
|
|
230
|
+
/context:
|
|
231
|
+
post:
|
|
232
|
+
summary: "Get mission-aligned context for bot"
|
|
233
|
+
parameters:
|
|
234
|
+
- name: bot_id
|
|
235
|
+
type: string
|
|
236
|
+
description: "Unique bot identifier"
|
|
237
|
+
- name: mission
|
|
238
|
+
type: string
|
|
239
|
+
enum: [security, inspection, monitoring, maintenance]
|
|
240
|
+
- name: location
|
|
241
|
+
type: object
|
|
242
|
+
properties:
|
|
243
|
+
lat: number
|
|
244
|
+
lon: number
|
|
245
|
+
responses:
|
|
246
|
+
200:
|
|
247
|
+
schema: Context
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Integration with Claude Code / Copilot
|
|
253
|
+
|
|
254
|
+
### Example: Claude Code Generates Inspection Bot
|
|
255
|
+
|
|
256
|
+
**Prompt:**
|
|
257
|
+
```
|
|
258
|
+
Create an inspection bot that:
|
|
259
|
+
1. Queries PyTerrainMap for building damage
|
|
260
|
+
2. Plans inspection route (avoid anomalies)
|
|
261
|
+
3. Documents findings
|
|
262
|
+
4. Returns damage report
|
|
263
|
+
|
|
264
|
+
Use PyTerrainAI to get mission context.
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Claude Code generates:**
|
|
268
|
+
```python
|
|
269
|
+
from pyterrain_ai import PyTerrainAI, Mission, DetailLevel
|
|
270
|
+
from pyterrain_map import PyTerrainMap
|
|
271
|
+
|
|
272
|
+
class InspectionBot:
|
|
273
|
+
def __init__(self, bot_id: str):
|
|
274
|
+
self.bot_id = bot_id
|
|
275
|
+
self.map = PyTerrainMap()
|
|
276
|
+
self.ai = PyTerrainAI(self.map)
|
|
277
|
+
|
|
278
|
+
async def inspect_building(self, location: GeoPoint) -> dict:
|
|
279
|
+
# Query for damage context
|
|
280
|
+
context = await self.ai.get_context(
|
|
281
|
+
bot_id=self.bot_id,
|
|
282
|
+
mission=Mission.INSPECTION,
|
|
283
|
+
location=location,
|
|
284
|
+
detail_level=DetailLevel.REGIONAL
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
# Find damage zones
|
|
288
|
+
damage = [a for a in context.anomalies if "damage" in a.type]
|
|
289
|
+
|
|
290
|
+
# Visit each damage zone
|
|
291
|
+
findings = []
|
|
292
|
+
for zone in damage:
|
|
293
|
+
detailed = await self.ai.get_context(
|
|
294
|
+
bot_id=self.bot_id,
|
|
295
|
+
mission=Mission.INSPECTION,
|
|
296
|
+
location=zone.location,
|
|
297
|
+
detail_level=DetailLevel.DETAILED
|
|
298
|
+
)
|
|
299
|
+
findings.append(self._document_damage(zone, detailed))
|
|
300
|
+
|
|
301
|
+
return {"bot": self.bot_id, "findings": findings}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Why this works:
|
|
305
|
+
- ✅ Type hints guide code generation
|
|
306
|
+
- ✅ Clear docstrings explain what functions do
|
|
307
|
+
- ✅ Example usage shows patterns
|
|
308
|
+
- ✅ Predictable API (no hidden state)
|
|
309
|
+
- ✅ Returns structured data (JSON-serializable)
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Principles for AI Compatibility
|
|
314
|
+
|
|
315
|
+
### 1. Type Hints Required
|
|
316
|
+
|
|
317
|
+
Every parameter and return value must have explicit type.
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
# ✅ GOOD
|
|
321
|
+
async def query(location: GeoPoint, radius_m: float) -> list[Observation]:
|
|
322
|
+
...
|
|
323
|
+
|
|
324
|
+
# ❌ BAD
|
|
325
|
+
async def query(location, radius_m):
|
|
326
|
+
...
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 2. No Magic or Implicit Behavior
|
|
330
|
+
|
|
331
|
+
AI can't infer intent. Be explicit.
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
# ✅ GOOD: AI knows what happens
|
|
335
|
+
context = await ai.get_context(
|
|
336
|
+
bot_id=bot_id,
|
|
337
|
+
mission=Mission.SECURITY,
|
|
338
|
+
location=location
|
|
339
|
+
)
|
|
340
|
+
# Returns: filtered, decayed, anomaly-flagged context
|
|
341
|
+
|
|
342
|
+
# ❌ BAD: AI might not know what query() does
|
|
343
|
+
data = await map.query(location)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### 3. Structured Returns
|
|
347
|
+
|
|
348
|
+
Return dataclasses or pydantic models, not dicts or tuples.
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
# ✅ GOOD: AI can introspect structure
|
|
352
|
+
@dataclass
|
|
353
|
+
class Context:
|
|
354
|
+
observations: list[Observation]
|
|
355
|
+
anomalies: list[Anomaly]
|
|
356
|
+
suggested_actions: list[str]
|
|
357
|
+
|
|
358
|
+
# ❌ BAD: AI can't know structure
|
|
359
|
+
return {
|
|
360
|
+
"data": [...],
|
|
361
|
+
"issues": [...],
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 4. Comprehensive Error Handling
|
|
366
|
+
|
|
367
|
+
Explicit exceptions that AI can catch and handle.
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
# ✅ GOOD: AI knows what can go wrong
|
|
371
|
+
try:
|
|
372
|
+
context = await ai.get_context(...)
|
|
373
|
+
except PermissionError:
|
|
374
|
+
print("Bot not authorized for this mission")
|
|
375
|
+
except ValueError:
|
|
376
|
+
print("Invalid mission type")
|
|
377
|
+
|
|
378
|
+
# ❌ BAD: Generic exception
|
|
379
|
+
except Exception as e:
|
|
380
|
+
print("Something went wrong")
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 5. Default Values for Common Cases
|
|
384
|
+
|
|
385
|
+
AI should be able to call with minimal args.
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
# ✅ GOOD: AI can call with just required params
|
|
389
|
+
context = await ai.get_context(
|
|
390
|
+
bot_id="bot_1",
|
|
391
|
+
mission=Mission.SECURITY,
|
|
392
|
+
location=GeoPoint(40.123, -74.567)
|
|
393
|
+
)
|
|
394
|
+
# Uses sensible defaults: radius_m=50, detail_level=REGIONAL
|
|
395
|
+
|
|
396
|
+
# ❌ BAD: Requires many parameters
|
|
397
|
+
context = await ai.get_context(
|
|
398
|
+
bot_id="bot_1",
|
|
399
|
+
mission="security",
|
|
400
|
+
lat=40.123,
|
|
401
|
+
lon=-74.567,
|
|
402
|
+
radius_m=50.0,
|
|
403
|
+
start_time=1234567890,
|
|
404
|
+
end_time=1234567900,
|
|
405
|
+
max_observations=100,
|
|
406
|
+
min_confidence=0.5,
|
|
407
|
+
)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Testing for AI Usage
|
|
413
|
+
|
|
414
|
+
Add tests that verify AI can call the API correctly:
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
async def test_ai_can_query_context():
|
|
418
|
+
"""Verify AI agents can call get_context"""
|
|
419
|
+
ai = PyTerrainAI(map_service)
|
|
420
|
+
|
|
421
|
+
# Minimal call (like AI would)
|
|
422
|
+
context = await ai.get_context(
|
|
423
|
+
bot_id="bot_1",
|
|
424
|
+
mission=Mission.SECURITY,
|
|
425
|
+
location=GeoPoint(40.123, -74.567)
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
# Verify structure is what AI expects
|
|
429
|
+
assert hasattr(context, 'observations')
|
|
430
|
+
assert hasattr(context, 'anomalies')
|
|
431
|
+
assert hasattr(context, 'suggested_actions')
|
|
432
|
+
assert isinstance(context.observations, list)
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Documentation for AI
|
|
438
|
+
|
|
439
|
+
Create a guide for LLMs to understand the system:
|
|
440
|
+
|
|
441
|
+
```markdown
|
|
442
|
+
# PyTerrain for AI Systems
|
|
443
|
+
|
|
444
|
+
PyTerrain is a collaborative terrain mapping system designed for autonomous AI agents.
|
|
445
|
+
|
|
446
|
+
## Quick Start for AI Agents
|
|
447
|
+
|
|
448
|
+
1. **Import the libraries**
|
|
449
|
+
```python
|
|
450
|
+
from pyterrain_map import PyTerrainMap, Observation, SensorType
|
|
451
|
+
from pyterrain_ai import PyTerrainAI, Mission
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
2. **Query for context**
|
|
455
|
+
```python
|
|
456
|
+
context = await ai.get_context(bot_id, mission, location)
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
3. **Process context**
|
|
460
|
+
```python
|
|
461
|
+
for anomaly in context.anomalies:
|
|
462
|
+
# Decide what to do based on anomaly
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
4. **Push observations**
|
|
466
|
+
```python
|
|
467
|
+
await map_service.push_observation(Observation(...))
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
## API Reference
|
|
471
|
+
|
|
472
|
+
[Full API docs with all type signatures and examples]
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## Summary
|
|
478
|
+
|
|
479
|
+
PyTerrain is designed so that:
|
|
480
|
+
- ✅ Claude Code can generate bot implementations
|
|
481
|
+
- ✅ Copilot can suggest PyTerrain calls
|
|
482
|
+
- ✅ Codex can write integration code
|
|
483
|
+
- ✅ LLMs understand the API from docs
|
|
484
|
+
- ✅ Type hints guide code generation
|
|
485
|
+
- ✅ Examples show patterns
|
|
486
|
+
- ✅ Errors are explicit and catchable
|
|
487
|
+
|
|
488
|
+
This is **API design for the AI era**.
|