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.
Files changed (84) hide show
  1. devagent_physical_engine/__init__.py +44 -0
  2. devagent_physical_engine/agent/__init__.py +40 -0
  3. devagent_physical_engine/agent/compiler.py +285 -0
  4. devagent_physical_engine/agent/contracts.py +129 -0
  5. devagent_physical_engine/agent/coordinator.py +108 -0
  6. devagent_physical_engine/agent/critic.py +72 -0
  7. devagent_physical_engine/agent/evidence.py +34 -0
  8. devagent_physical_engine/agent/interpreter.py +179 -0
  9. devagent_physical_engine/agent/planner.py +105 -0
  10. devagent_physical_engine/agent/recovery.py +54 -0
  11. devagent_physical_engine/agent/routing.py +76 -0
  12. devagent_physical_engine/agent/runtime.py +270 -0
  13. devagent_physical_engine/agent/semantic.py +304 -0
  14. devagent_physical_engine/agent/structured.py +423 -0
  15. devagent_physical_engine/ai_cli.py +226 -0
  16. devagent_physical_engine/cli.py +392 -0
  17. devagent_physical_engine/doctor.py +20 -0
  18. devagent_physical_engine/engineering_agent.py +243 -0
  19. devagent_physical_engine/engineering_request.py +630 -0
  20. devagent_physical_engine/execution.py +90 -0
  21. devagent_physical_engine/models.py +143 -0
  22. devagent_physical_engine/operating_envelope.py +120 -0
  23. devagent_physical_engine/optimization/__init__.py +50 -0
  24. devagent_physical_engine/optimization/benchmark.py +122 -0
  25. devagent_physical_engine/optimization/candidates.py +198 -0
  26. devagent_physical_engine/optimization/contracts.py +235 -0
  27. devagent_physical_engine/optimization/evaluator.py +107 -0
  28. devagent_physical_engine/optimization/evidence.py +53 -0
  29. devagent_physical_engine/optimization/experience.py +105 -0
  30. devagent_physical_engine/optimization/measured.py +125 -0
  31. devagent_physical_engine/optimization/optimizer.py +215 -0
  32. devagent_physical_engine/optimization/orchestrator.py +155 -0
  33. devagent_physical_engine/physical_campaign.py +413 -0
  34. devagent_physical_engine/physical_evidence.py +214 -0
  35. devagent_physical_engine/physical_motion.py +196 -0
  36. devagent_physical_engine/planning.py +80 -0
  37. devagent_physical_engine/preexecution_contract.py +65 -0
  38. devagent_physical_engine/provider_adapters/__init__.py +22 -0
  39. devagent_physical_engine/provider_adapters/anthropic.py +112 -0
  40. devagent_physical_engine/provider_adapters/common.py +187 -0
  41. devagent_physical_engine/provider_adapters/factory.py +20 -0
  42. devagent_physical_engine/provider_adapters/gemini.py +126 -0
  43. devagent_physical_engine/provider_adapters/openai.py +95 -0
  44. devagent_physical_engine/provider_qualification.py +268 -0
  45. devagent_physical_engine/providers.py +94 -0
  46. devagent_physical_engine/qualification.py +44 -0
  47. devagent_physical_engine/qualification_cli.py +195 -0
  48. devagent_physical_engine/qualification_harness.py +917 -0
  49. devagent_physical_engine/robot_platform.py +411 -0
  50. devagent_physical_engine/robots.py +76 -0
  51. devagent_physical_engine/ros2/__init__.py +35 -0
  52. devagent_physical_engine/ros2/acceptance.py +324 -0
  53. devagent_physical_engine/ros2/commands.py +175 -0
  54. devagent_physical_engine/ros2/doctor.py +116 -0
  55. devagent_physical_engine/ros2/fk_probe.py +83 -0
  56. devagent_physical_engine/ros2/frame_alignment.py +61 -0
  57. devagent_physical_engine/ros2/gazebo_world.py +125 -0
  58. devagent_physical_engine/ros2/joint_state_recorder.py +64 -0
  59. devagent_physical_engine/ros2/measured_motion.py +233 -0
  60. devagent_physical_engine/ros2/moveit_scene.py +121 -0
  61. devagent_physical_engine/ros2/preexecution.py +113 -0
  62. devagent_physical_engine/ros2/qualification.py +81 -0
  63. devagent_physical_engine/ros2/qualification_v10.py +252 -0
  64. devagent_physical_engine/ros2/scene_probe.py +219 -0
  65. devagent_physical_engine/ros2/state_validity_probe.py +125 -0
  66. devagent_physical_engine/ros2/tf_probe.py +51 -0
  67. devagent_physical_engine/ros2/trajectory.py +188 -0
  68. devagent_physical_engine/ros2/ur5e.py +59 -0
  69. devagent_physical_engine/ros2/ur5e_adapter.py +349 -0
  70. devagent_physical_engine/ros2/ur5e_v10_adapter.py +292 -0
  71. devagent_physical_engine/setup_profile.py +356 -0
  72. devagent_physical_engine/simulation.py +32 -0
  73. devagent_physical_engine/simulation_platform.py +269 -0
  74. devagent_physical_engine/trajectory_qualification.py +201 -0
  75. devagent_physical_engine/twin.py +939 -0
  76. devagent_physical_engine/twin_builder.py +309 -0
  77. devagent_physical_engine/twin_materialization.py +404 -0
  78. devagent_physical_engine/verification.py +46 -0
  79. devagent_physical_engine-0.10.0.dist-info/METADATA +315 -0
  80. devagent_physical_engine-0.10.0.dist-info/RECORD +84 -0
  81. devagent_physical_engine-0.10.0.dist-info/WHEEL +5 -0
  82. devagent_physical_engine-0.10.0.dist-info/entry_points.txt +3 -0
  83. devagent_physical_engine-0.10.0.dist-info/licenses/NOTICE +2 -0
  84. 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