devagent-physical-engine 0.10.0__py3-none-any.whl
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.
- devagent_physical_engine/__init__.py +44 -0
- devagent_physical_engine/agent/__init__.py +40 -0
- devagent_physical_engine/agent/compiler.py +285 -0
- devagent_physical_engine/agent/contracts.py +129 -0
- devagent_physical_engine/agent/coordinator.py +108 -0
- devagent_physical_engine/agent/critic.py +72 -0
- devagent_physical_engine/agent/evidence.py +34 -0
- devagent_physical_engine/agent/interpreter.py +179 -0
- devagent_physical_engine/agent/planner.py +105 -0
- devagent_physical_engine/agent/recovery.py +54 -0
- devagent_physical_engine/agent/routing.py +76 -0
- devagent_physical_engine/agent/runtime.py +270 -0
- devagent_physical_engine/agent/semantic.py +304 -0
- devagent_physical_engine/agent/structured.py +423 -0
- devagent_physical_engine/ai_cli.py +226 -0
- devagent_physical_engine/cli.py +392 -0
- devagent_physical_engine/doctor.py +20 -0
- devagent_physical_engine/engineering_agent.py +243 -0
- devagent_physical_engine/engineering_request.py +630 -0
- devagent_physical_engine/execution.py +90 -0
- devagent_physical_engine/models.py +143 -0
- devagent_physical_engine/operating_envelope.py +120 -0
- devagent_physical_engine/optimization/__init__.py +50 -0
- devagent_physical_engine/optimization/benchmark.py +122 -0
- devagent_physical_engine/optimization/candidates.py +198 -0
- devagent_physical_engine/optimization/contracts.py +235 -0
- devagent_physical_engine/optimization/evaluator.py +107 -0
- devagent_physical_engine/optimization/evidence.py +53 -0
- devagent_physical_engine/optimization/experience.py +105 -0
- devagent_physical_engine/optimization/measured.py +125 -0
- devagent_physical_engine/optimization/optimizer.py +215 -0
- devagent_physical_engine/optimization/orchestrator.py +155 -0
- devagent_physical_engine/physical_campaign.py +413 -0
- devagent_physical_engine/physical_evidence.py +214 -0
- devagent_physical_engine/physical_motion.py +196 -0
- devagent_physical_engine/planning.py +80 -0
- devagent_physical_engine/preexecution_contract.py +65 -0
- devagent_physical_engine/provider_adapters/__init__.py +22 -0
- devagent_physical_engine/provider_adapters/anthropic.py +112 -0
- devagent_physical_engine/provider_adapters/common.py +187 -0
- devagent_physical_engine/provider_adapters/factory.py +20 -0
- devagent_physical_engine/provider_adapters/gemini.py +126 -0
- devagent_physical_engine/provider_adapters/openai.py +95 -0
- devagent_physical_engine/provider_qualification.py +268 -0
- devagent_physical_engine/providers.py +94 -0
- devagent_physical_engine/qualification.py +44 -0
- devagent_physical_engine/qualification_cli.py +195 -0
- devagent_physical_engine/qualification_harness.py +917 -0
- devagent_physical_engine/robot_platform.py +411 -0
- devagent_physical_engine/robots.py +76 -0
- devagent_physical_engine/ros2/__init__.py +35 -0
- devagent_physical_engine/ros2/acceptance.py +324 -0
- devagent_physical_engine/ros2/commands.py +175 -0
- devagent_physical_engine/ros2/doctor.py +116 -0
- devagent_physical_engine/ros2/fk_probe.py +83 -0
- devagent_physical_engine/ros2/frame_alignment.py +61 -0
- devagent_physical_engine/ros2/gazebo_world.py +125 -0
- devagent_physical_engine/ros2/joint_state_recorder.py +64 -0
- devagent_physical_engine/ros2/measured_motion.py +233 -0
- devagent_physical_engine/ros2/moveit_scene.py +121 -0
- devagent_physical_engine/ros2/preexecution.py +113 -0
- devagent_physical_engine/ros2/qualification.py +81 -0
- devagent_physical_engine/ros2/qualification_v10.py +252 -0
- devagent_physical_engine/ros2/scene_probe.py +219 -0
- devagent_physical_engine/ros2/state_validity_probe.py +125 -0
- devagent_physical_engine/ros2/tf_probe.py +51 -0
- devagent_physical_engine/ros2/trajectory.py +188 -0
- devagent_physical_engine/ros2/ur5e.py +59 -0
- devagent_physical_engine/ros2/ur5e_adapter.py +349 -0
- devagent_physical_engine/ros2/ur5e_v10_adapter.py +292 -0
- devagent_physical_engine/setup_profile.py +356 -0
- devagent_physical_engine/simulation.py +32 -0
- devagent_physical_engine/simulation_platform.py +269 -0
- devagent_physical_engine/trajectory_qualification.py +201 -0
- devagent_physical_engine/twin.py +939 -0
- devagent_physical_engine/twin_builder.py +309 -0
- devagent_physical_engine/twin_materialization.py +404 -0
- devagent_physical_engine/verification.py +46 -0
- devagent_physical_engine-0.10.0.dist-info/METADATA +315 -0
- devagent_physical_engine-0.10.0.dist-info/RECORD +84 -0
- devagent_physical_engine-0.10.0.dist-info/WHEEL +5 -0
- devagent_physical_engine-0.10.0.dist-info/entry_points.txt +3 -0
- devagent_physical_engine-0.10.0.dist-info/licenses/NOTICE +2 -0
- devagent_physical_engine-0.10.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
from .qualification_harness import (
|
|
7
|
+
QualificationError,
|
|
8
|
+
QualificationStore,
|
|
9
|
+
base_case,
|
|
10
|
+
compare_summaries,
|
|
11
|
+
generate_fuzz_cases,
|
|
12
|
+
load_scenario,
|
|
13
|
+
load_scenario_suite,
|
|
14
|
+
load_summary,
|
|
15
|
+
replay_case,
|
|
16
|
+
run_cases,
|
|
17
|
+
variation_space_size,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
DEFAULT_QUALIFICATION_ROOT = "~/.devagent/qualification"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def add_qualification_parsers(sub: argparse._SubParsersAction) -> None:
|
|
25
|
+
test = sub.add_parser(
|
|
26
|
+
"test",
|
|
27
|
+
help="Run one deterministic qualification scenario and record evidence",
|
|
28
|
+
)
|
|
29
|
+
test.add_argument("scenario")
|
|
30
|
+
test.add_argument("--output-dir", default=DEFAULT_QUALIFICATION_ROOT)
|
|
31
|
+
|
|
32
|
+
suite = sub.add_parser(
|
|
33
|
+
"test-suite",
|
|
34
|
+
help="Run all YAML/JSON scenarios in a directory",
|
|
35
|
+
)
|
|
36
|
+
suite.add_argument("scenario_dir")
|
|
37
|
+
suite.add_argument("--output-dir", default=DEFAULT_QUALIFICATION_ROOT)
|
|
38
|
+
|
|
39
|
+
fuzz = sub.add_parser(
|
|
40
|
+
"fuzz",
|
|
41
|
+
help="Run seeded dynamic deterministic-model qualification cases",
|
|
42
|
+
)
|
|
43
|
+
fuzz.add_argument("scenario")
|
|
44
|
+
fuzz.add_argument("--runs", type=int, default=1000)
|
|
45
|
+
fuzz.add_argument("--seed", type=int, default=0)
|
|
46
|
+
fuzz.add_argument("--output-dir", default=DEFAULT_QUALIFICATION_ROOT)
|
|
47
|
+
|
|
48
|
+
replay = sub.add_parser(
|
|
49
|
+
"replay",
|
|
50
|
+
help="Re-run an exact recorded deterministic qualification case",
|
|
51
|
+
)
|
|
52
|
+
replay.add_argument("case_id")
|
|
53
|
+
replay.add_argument("--run", default=None)
|
|
54
|
+
replay.add_argument("--store-root", default=DEFAULT_QUALIFICATION_ROOT)
|
|
55
|
+
replay.add_argument(
|
|
56
|
+
"--visual",
|
|
57
|
+
action="store_true",
|
|
58
|
+
help="Request visual replay; v0.6 fails closed because deterministic cases do not encode Gazebo geometry",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
compare = sub.add_parser(
|
|
62
|
+
"compare",
|
|
63
|
+
help="Compare two qualification summaries on the same case corpus",
|
|
64
|
+
)
|
|
65
|
+
compare.add_argument("baseline")
|
|
66
|
+
compare.add_argument("candidate")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _emit_run(summary, run_dir, *, extra: dict | None = None) -> None:
|
|
70
|
+
payload = {
|
|
71
|
+
"summary": summary.to_dict(),
|
|
72
|
+
"run_dir": str(run_dir),
|
|
73
|
+
}
|
|
74
|
+
if extra:
|
|
75
|
+
payload.update(extra)
|
|
76
|
+
print(json.dumps(payload, indent=2))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _test(args: argparse.Namespace) -> int:
|
|
80
|
+
scenario = load_scenario(args.scenario)
|
|
81
|
+
cases = (base_case(scenario),)
|
|
82
|
+
results, summary = run_cases(cases, mode="test", seed=0)
|
|
83
|
+
run_dir = QualificationStore(args.output_dir).write_run(
|
|
84
|
+
scenarios=(scenario,),
|
|
85
|
+
results=results,
|
|
86
|
+
summary=summary,
|
|
87
|
+
)
|
|
88
|
+
_emit_run(summary, run_dir, extra={"result": results[0].to_dict()})
|
|
89
|
+
return 0 if summary.qualified else 10
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _test_suite(args: argparse.Namespace) -> int:
|
|
93
|
+
scenarios = load_scenario_suite(args.scenario_dir)
|
|
94
|
+
cases = tuple(
|
|
95
|
+
base_case(scenario, index=index, seed=0)
|
|
96
|
+
for index, scenario in enumerate(scenarios, start=1)
|
|
97
|
+
)
|
|
98
|
+
results, summary = run_cases(cases, mode="test-suite", seed=0)
|
|
99
|
+
run_dir = QualificationStore(args.output_dir).write_run(
|
|
100
|
+
scenarios=scenarios,
|
|
101
|
+
results=results,
|
|
102
|
+
summary=summary,
|
|
103
|
+
)
|
|
104
|
+
_emit_run(summary, run_dir)
|
|
105
|
+
return 0 if summary.qualified else 10
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _fuzz(args: argparse.Namespace) -> int:
|
|
109
|
+
scenario = load_scenario(args.scenario)
|
|
110
|
+
cases = generate_fuzz_cases(
|
|
111
|
+
scenario,
|
|
112
|
+
runs=args.runs,
|
|
113
|
+
seed=args.seed,
|
|
114
|
+
)
|
|
115
|
+
results, summary = run_cases(cases, mode="fuzz", seed=args.seed)
|
|
116
|
+
run_dir = QualificationStore(args.output_dir).write_run(
|
|
117
|
+
scenarios=(scenario,),
|
|
118
|
+
results=results,
|
|
119
|
+
summary=summary,
|
|
120
|
+
)
|
|
121
|
+
_emit_run(
|
|
122
|
+
summary,
|
|
123
|
+
run_dir,
|
|
124
|
+
extra={
|
|
125
|
+
"variation_space_size": variation_space_size(scenario),
|
|
126
|
+
"note": (
|
|
127
|
+
"deterministic_model qualification only; "
|
|
128
|
+
"physical_qualification remains false"
|
|
129
|
+
),
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
return 0 if summary.qualified else 10
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _replay(args: argparse.Namespace) -> int:
|
|
136
|
+
if args.visual:
|
|
137
|
+
print(
|
|
138
|
+
json.dumps(
|
|
139
|
+
{
|
|
140
|
+
"passed": False,
|
|
141
|
+
"failure_code": "visual_replay_not_supported_v06",
|
|
142
|
+
"detail": (
|
|
143
|
+
"Recorded v0.6 qualification cases exercise the deterministic "
|
|
144
|
+
"model backend and do not encode Gazebo world geometry. "
|
|
145
|
+
"Exact deterministic replay is supported without --visual."
|
|
146
|
+
),
|
|
147
|
+
},
|
|
148
|
+
indent=2,
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
return 12
|
|
152
|
+
payload = replay_case(
|
|
153
|
+
args.case_id,
|
|
154
|
+
run_ref=args.run,
|
|
155
|
+
store_root=args.store_root,
|
|
156
|
+
)
|
|
157
|
+
print(json.dumps(payload, indent=2))
|
|
158
|
+
return 0 if payload["reproduced"] else 11
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _compare(args: argparse.Namespace) -> int:
|
|
162
|
+
payload = compare_summaries(
|
|
163
|
+
load_summary(args.baseline),
|
|
164
|
+
load_summary(args.candidate),
|
|
165
|
+
)
|
|
166
|
+
print(json.dumps(payload, indent=2))
|
|
167
|
+
if not payload["comparable"]:
|
|
168
|
+
return 14
|
|
169
|
+
return 0 if payload["passed"] else 13
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def run_qualification_command(args: argparse.Namespace) -> int | None:
|
|
173
|
+
try:
|
|
174
|
+
if args.command == "test":
|
|
175
|
+
return _test(args)
|
|
176
|
+
if args.command == "test-suite":
|
|
177
|
+
return _test_suite(args)
|
|
178
|
+
if args.command == "fuzz":
|
|
179
|
+
return _fuzz(args)
|
|
180
|
+
if args.command == "replay":
|
|
181
|
+
return _replay(args)
|
|
182
|
+
if args.command == "compare":
|
|
183
|
+
return _compare(args)
|
|
184
|
+
except QualificationError as exc:
|
|
185
|
+
print(
|
|
186
|
+
json.dumps(
|
|
187
|
+
{
|
|
188
|
+
"passed": False,
|
|
189
|
+
"failure_code": str(exc),
|
|
190
|
+
},
|
|
191
|
+
indent=2,
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
return 10
|
|
195
|
+
return None
|