devagent-physical-engine 0.11.2__tar.gz → 0.11.3__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 (136) hide show
  1. {devagent_physical_engine-0.11.2/src/devagent_physical_engine.egg-info → devagent_physical_engine-0.11.3}/PKG-INFO +7 -5
  2. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/README.md +6 -4
  3. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/pyproject.toml +1 -1
  4. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/__init__.py +1 -1
  5. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/provider_adapters/openai.py +82 -2
  6. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3/src/devagent_physical_engine.egg-info}/PKG-INFO +7 -5
  7. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine.egg-info/SOURCES.txt +1 -0
  8. devagent_physical_engine-0.11.3/tests/test_openai_strict_schema_v0113.py +68 -0
  9. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/NOTICE +0 -0
  10. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/setup.cfg +0 -0
  11. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/__init__.py +0 -0
  12. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/compiler.py +0 -0
  13. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/contracts.py +0 -0
  14. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/coordinator.py +0 -0
  15. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/critic.py +0 -0
  16. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/evidence.py +0 -0
  17. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/interpreter.py +0 -0
  18. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/planner.py +0 -0
  19. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/recovery.py +0 -0
  20. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/routing.py +0 -0
  21. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/runtime.py +0 -0
  22. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/semantic.py +0 -0
  23. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/agent/structured.py +0 -0
  24. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ai_cli.py +0 -0
  25. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/cli.py +0 -0
  26. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/continuous_clearance.py +0 -0
  27. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/doctor.py +0 -0
  28. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/engineering_agent.py +0 -0
  29. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/engineering_request.py +0 -0
  30. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/execution.py +0 -0
  31. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/models.py +0 -0
  32. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/operating_envelope.py +0 -0
  33. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/__init__.py +0 -0
  34. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/benchmark.py +0 -0
  35. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/candidates.py +0 -0
  36. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/contracts.py +0 -0
  37. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/evaluator.py +0 -0
  38. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/evidence.py +0 -0
  39. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/experience.py +0 -0
  40. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/measured.py +0 -0
  41. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/optimizer.py +0 -0
  42. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/optimization/orchestrator.py +0 -0
  43. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/physical_campaign.py +0 -0
  44. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/physical_evidence.py +0 -0
  45. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/physical_motion.py +0 -0
  46. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/planning.py +0 -0
  47. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/preexecution_contract.py +0 -0
  48. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/provider_adapters/__init__.py +0 -0
  49. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/provider_adapters/anthropic.py +0 -0
  50. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/provider_adapters/common.py +0 -0
  51. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/provider_adapters/factory.py +0 -0
  52. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/provider_adapters/gemini.py +0 -0
  53. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/provider_qualification.py +0 -0
  54. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/providers.py +0 -0
  55. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/qualification.py +0 -0
  56. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/qualification_cli.py +0 -0
  57. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/qualification_harness.py +0 -0
  58. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/robot_platform.py +0 -0
  59. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/robots.py +0 -0
  60. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/__init__.py +0 -0
  61. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/acceptance.py +0 -0
  62. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/commands.py +0 -0
  63. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/continuous_clearance_probe.py +0 -0
  64. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/doctor.py +0 -0
  65. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/fk_probe.py +0 -0
  66. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/frame_alignment.py +0 -0
  67. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/gazebo_world.py +0 -0
  68. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/joint_state_recorder.py +0 -0
  69. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/measured_motion.py +0 -0
  70. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/moveit_scene.py +0 -0
  71. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/preexecution.py +0 -0
  72. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/qualification.py +0 -0
  73. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/qualification_v10.py +0 -0
  74. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/qualification_v11.py +0 -0
  75. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/scene_probe.py +0 -0
  76. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/state_validity_probe.py +0 -0
  77. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/tf_probe.py +0 -0
  78. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/tool_scene.py +0 -0
  79. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/tool_scene_probe.py +0 -0
  80. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/trajectory.py +0 -0
  81. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/ur5e.py +0 -0
  82. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/ur5e_adapter.py +0 -0
  83. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/ur5e_v10_adapter.py +0 -0
  84. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/workpiece_scene.py +0 -0
  85. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/ros2/workpiece_scene_probe.py +0 -0
  86. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/setup_profile.py +0 -0
  87. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/sim_real_qualification.py +0 -0
  88. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/simulation.py +0 -0
  89. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/simulation_platform.py +0 -0
  90. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/tool_collision.py +0 -0
  91. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/trajectory_qualification.py +0 -0
  92. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/twin.py +0 -0
  93. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/twin_builder.py +0 -0
  94. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/twin_materialization.py +0 -0
  95. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/verification.py +0 -0
  96. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine/workpiece_lifecycle.py +0 -0
  97. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine.egg-info/dependency_links.txt +0 -0
  98. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine.egg-info/entry_points.txt +0 -0
  99. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine.egg-info/requires.txt +0 -0
  100. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/src/devagent_physical_engine.egg-info/top_level.txt +0 -0
  101. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_agent_core.py +0 -0
  102. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_agent_semantic_hardening.py +0 -0
  103. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_ai_cli.py +0 -0
  104. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_ai_cli_v07.py +0 -0
  105. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_continuous_clearance_v011.py +0 -0
  106. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_core.py +0 -0
  107. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_engineering_request_v07.py +0 -0
  108. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_interpreter_profiles_v08.py +0 -0
  109. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_live_provider_qualification.py +0 -0
  110. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_measured_motion_v10.py +0 -0
  111. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_natural_language_agent_v07.py +0 -0
  112. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_optimization_v05.py +0 -0
  113. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_physical_campaign_v09.py +0 -0
  114. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_physical_evidence_v09.py +0 -0
  115. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_physical_motion_v09.py +0 -0
  116. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_preexecution_contract_v10.py +0 -0
  117. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_provider_and_qualification.py +0 -0
  118. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_qualification_cli_lifecycle_v06.py +0 -0
  119. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_qualification_harness_v06.py +0 -0
  120. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_real_provider_adapters.py +0 -0
  121. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_robot_platform_v08.py +0 -0
  122. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_ros2_production_receipts_v011.py +0 -0
  123. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_ros2_simulation.py +0 -0
  124. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_ros_trajectory_v09.py +0 -0
  125. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_setup_profile.py +0 -0
  126. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_sim_real_qualification_v011.py +0 -0
  127. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_simulation_platform_v08.py +0 -0
  128. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_tool_collision_v011.py +0 -0
  129. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_trajectory_qualification_v09.py +0 -0
  130. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_twin_materialization_v10.py +0 -0
  131. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_twin_v08.py +0 -0
  132. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_ur5e_adapter_scopes_v09.py +0 -0
  133. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_ur5e_v10_adapter_scopes.py +0 -0
  134. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_v052_stabilization.py +0 -0
  135. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_v08_catalog_mapping_regression.py +0 -0
  136. {devagent_physical_engine-0.11.2 → devagent_physical_engine-0.11.3}/tests/test_workpiece_lifecycle_v011.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devagent-physical-engine
3
- Version: 0.11.2
3
+ Version: 0.11.3
4
4
  Summary: Verification-first agentic planning runtime for robotic and industrial automation.
5
5
  Author: Tom Ha
6
6
  License: All Rights Reserved
@@ -49,10 +49,12 @@ DevAgent Smart Physical Engine adds AI-assisted engineering to existing automati
49
49
 
50
50
  ## Current version
51
51
 
52
- **v0.11.2 — Beta software / evidence-gated physical runtime**
52
+ **v0.11.3 — Beta software / evidence-gated physical runtime**
53
53
 
54
54
  The Python software stack is regression-tested on Python 3.11, 3.12, and 3.13 with separate static/coverage, package-install, and runtime dependency security gates. The UR5e Gazebo/MoveIt path now contains production-candidate continuous-clearance, tool-collision, and workpiece-lifecycle capabilities, but those physical-simulation scopes remain **EXPERIMENTAL until the executable target-workstation v0.11 campaign passes**.
55
55
 
56
+ v0.11.3 also normalizes provider-neutral agent schemas at the OpenAI transport boundary so strict Structured Outputs can represent DevAgent optional fields without changing Anthropic/Gemini or deterministic core semantics.
57
+
56
58
  Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
57
59
 
58
60
  ## v0.11 capability status
@@ -195,16 +197,16 @@ export ANTHROPIC_API_KEY='...'
195
197
  export GEMINI_API_KEY='...'
196
198
  ```
197
199
 
198
- Examples:
200
+ Examples use the currently supported deterministic goal action `load`:
199
201
 
200
202
  ```bash
201
203
  devagent-physical-ai doctor --provider openai
202
204
  devagent-physical-ai qualify --provider openai --model <model-id>
203
205
  devagent-physical-ai request \
204
- "Use a UR5e to move a part from conveyor_a to cnc_04" \
206
+ "Use a UR5e to load BOX_101 from conveyor_a to cnc_04. Simulate and verify the plan." \
205
207
  --provider openai --model <model-id>
206
208
  devagent-physical-ai engineer \
207
- "Use a UR5e to move a part from conveyor_a to cnc_04" \
209
+ "Use a UR5e to load BOX_101 from conveyor_a to cnc_04. Simulate and verify the plan." \
208
210
  --provider openai --model <model-id>
209
211
  ```
210
212
 
@@ -8,10 +8,12 @@ DevAgent Smart Physical Engine adds AI-assisted engineering to existing automati
8
8
 
9
9
  ## Current version
10
10
 
11
- **v0.11.2 — Beta software / evidence-gated physical runtime**
11
+ **v0.11.3 — Beta software / evidence-gated physical runtime**
12
12
 
13
13
  The Python software stack is regression-tested on Python 3.11, 3.12, and 3.13 with separate static/coverage, package-install, and runtime dependency security gates. The UR5e Gazebo/MoveIt path now contains production-candidate continuous-clearance, tool-collision, and workpiece-lifecycle capabilities, but those physical-simulation scopes remain **EXPERIMENTAL until the executable target-workstation v0.11 campaign passes**.
14
14
 
15
+ v0.11.3 also normalizes provider-neutral agent schemas at the OpenAI transport boundary so strict Structured Outputs can represent DevAgent optional fields without changing Anthropic/Gemini or deterministic core semantics.
16
+
15
17
  Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
16
18
 
17
19
  ## v0.11 capability status
@@ -154,16 +156,16 @@ export ANTHROPIC_API_KEY='...'
154
156
  export GEMINI_API_KEY='...'
155
157
  ```
156
158
 
157
- Examples:
159
+ Examples use the currently supported deterministic goal action `load`:
158
160
 
159
161
  ```bash
160
162
  devagent-physical-ai doctor --provider openai
161
163
  devagent-physical-ai qualify --provider openai --model <model-id>
162
164
  devagent-physical-ai request \
163
- "Use a UR5e to move a part from conveyor_a to cnc_04" \
165
+ "Use a UR5e to load BOX_101 from conveyor_a to cnc_04. Simulate and verify the plan." \
164
166
  --provider openai --model <model-id>
165
167
  devagent-physical-ai engineer \
166
- "Use a UR5e to move a part from conveyor_a to cnc_04" \
168
+ "Use a UR5e to load BOX_101 from conveyor_a to cnc_04. Simulate and verify the plan." \
167
169
  --provider openai --model <model-id>
168
170
  ```
169
171
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devagent-physical-engine"
7
- version = "0.11.2"
7
+ version = "0.11.3"
8
8
  description = "Verification-first agentic planning runtime for robotic and industrial automation."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -41,4 +41,4 @@ __all__ = [
41
41
  "TwinValidator",
42
42
  ]
43
43
 
44
- __version__ = "0.11.2"
44
+ __version__ = "0.11.3"
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Callable
3
+ from typing import Any, Callable, Mapping
4
4
 
5
5
  from ..agent.contracts import ModelRequest, ModelResponse
6
6
  from ..agent.runtime import ProviderError, ProviderProtocolError, ProviderUnavailable
@@ -17,6 +17,86 @@ from .common import (
17
17
  )
18
18
 
19
19
 
20
+ def _nullable_openai_schema(value: Mapping[str, Any]) -> dict[str, Any]:
21
+ """Return an OpenAI-strict-compatible nullable schema for an optional field."""
22
+
23
+ result = dict(value)
24
+ schema_type = result.get("type")
25
+ if isinstance(schema_type, str):
26
+ if schema_type != "null":
27
+ result["type"] = [schema_type, "null"]
28
+ return result
29
+ if isinstance(schema_type, list):
30
+ types = list(schema_type)
31
+ if "null" not in types:
32
+ types.append("null")
33
+ result["type"] = types
34
+ return result
35
+
36
+ enum = result.get("enum")
37
+ if isinstance(enum, list):
38
+ values = list(enum)
39
+ if None not in values:
40
+ values.append(None)
41
+ result["enum"] = values
42
+ return result
43
+
44
+ any_of = result.get("anyOf")
45
+ if isinstance(any_of, list):
46
+ branches = list(any_of)
47
+ if not any(
48
+ isinstance(branch, Mapping) and branch.get("type") == "null"
49
+ for branch in branches
50
+ ):
51
+ branches.append({"type": "null"})
52
+ result["anyOf"] = branches
53
+ return result
54
+
55
+ return {"anyOf": [result, {"type": "null"}]}
56
+
57
+
58
+ def _openai_strict_schema(schema: Mapping[str, Any]) -> dict[str, Any]:
59
+ """Normalize a provider-neutral schema for OpenAI strict Structured Outputs.
60
+
61
+ DevAgent's core schemas intentionally permit omitted optional fields because
62
+ Anthropic, Gemini, and deterministic parsers support that representation.
63
+ OpenAI strict Structured Outputs instead requires every property of every
64
+ object to appear in ``required``. Preserve provider-neutral core semantics by
65
+ making only those originally optional properties nullable in the OpenAI
66
+ transport schema, while keeping deterministic parsing/compilation as the
67
+ final authority.
68
+ """
69
+
70
+ clean = provider_schema(schema)
71
+
72
+ def normalize(value: Any) -> Any:
73
+ if isinstance(value, list):
74
+ return [normalize(item) for item in value]
75
+ if not isinstance(value, dict):
76
+ return value
77
+
78
+ result = {key: normalize(item) for key, item in value.items()}
79
+ properties = result.get("properties")
80
+ if isinstance(properties, dict):
81
+ required_raw = result.get("required", [])
82
+ required = set(required_raw) if isinstance(required_raw, list) else set()
83
+ normalized_properties: dict[str, Any] = {}
84
+ for name, property_schema in properties.items():
85
+ if name in required or not isinstance(property_schema, Mapping):
86
+ normalized_properties[name] = property_schema
87
+ else:
88
+ normalized_properties[name] = _nullable_openai_schema(property_schema)
89
+ result["properties"] = normalized_properties
90
+ result["required"] = list(normalized_properties)
91
+ result["additionalProperties"] = False
92
+ return result
93
+
94
+ normalized = normalize(clean)
95
+ if not isinstance(normalized, dict): # pragma: no cover - schema contract is mapping
96
+ raise TypeError("openai_schema_must_be_object")
97
+ return normalized
98
+
99
+
20
100
  class OpenAIProvider:
21
101
  provider_name = "openai"
22
102
 
@@ -58,7 +138,7 @@ class OpenAIProvider:
58
138
  "type": "json_schema",
59
139
  "name": f"devagent_{request.role.value}",
60
140
  "strict": True,
61
- "schema": provider_schema(request.output_schema),
141
+ "schema": _openai_strict_schema(request.output_schema),
62
142
  }
63
143
  },
64
144
  max_output_tokens=self._max_output_tokens,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devagent-physical-engine
3
- Version: 0.11.2
3
+ Version: 0.11.3
4
4
  Summary: Verification-first agentic planning runtime for robotic and industrial automation.
5
5
  Author: Tom Ha
6
6
  License: All Rights Reserved
@@ -49,10 +49,12 @@ DevAgent Smart Physical Engine adds AI-assisted engineering to existing automati
49
49
 
50
50
  ## Current version
51
51
 
52
- **v0.11.2 — Beta software / evidence-gated physical runtime**
52
+ **v0.11.3 — Beta software / evidence-gated physical runtime**
53
53
 
54
54
  The Python software stack is regression-tested on Python 3.11, 3.12, and 3.13 with separate static/coverage, package-install, and runtime dependency security gates. The UR5e Gazebo/MoveIt path now contains production-candidate continuous-clearance, tool-collision, and workpiece-lifecycle capabilities, but those physical-simulation scopes remain **EXPERIMENTAL until the executable target-workstation v0.11 campaign passes**.
55
55
 
56
+ v0.11.3 also normalizes provider-neutral agent schemas at the OpenAI transport boundary so strict Structured Outputs can represent DevAgent optional fields without changing Anthropic/Gemini or deterministic core semantics.
57
+
56
58
  Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
57
59
 
58
60
  ## v0.11 capability status
@@ -195,16 +197,16 @@ export ANTHROPIC_API_KEY='...'
195
197
  export GEMINI_API_KEY='...'
196
198
  ```
197
199
 
198
- Examples:
200
+ Examples use the currently supported deterministic goal action `load`:
199
201
 
200
202
  ```bash
201
203
  devagent-physical-ai doctor --provider openai
202
204
  devagent-physical-ai qualify --provider openai --model <model-id>
203
205
  devagent-physical-ai request \
204
- "Use a UR5e to move a part from conveyor_a to cnc_04" \
206
+ "Use a UR5e to load BOX_101 from conveyor_a to cnc_04. Simulate and verify the plan." \
205
207
  --provider openai --model <model-id>
206
208
  devagent-physical-ai engineer \
207
- "Use a UR5e to move a part from conveyor_a to cnc_04" \
209
+ "Use a UR5e to load BOX_101 from conveyor_a to cnc_04. Simulate and verify the plan." \
208
210
  --provider openai --model <model-id>
209
211
  ```
210
212
 
@@ -106,6 +106,7 @@ tests/test_interpreter_profiles_v08.py
106
106
  tests/test_live_provider_qualification.py
107
107
  tests/test_measured_motion_v10.py
108
108
  tests/test_natural_language_agent_v07.py
109
+ tests/test_openai_strict_schema_v0113.py
109
110
  tests/test_optimization_v05.py
110
111
  tests/test_physical_campaign_v09.py
111
112
  tests/test_physical_evidence_v09.py
@@ -0,0 +1,68 @@
1
+ from __future__ import annotations
2
+
3
+ import unittest
4
+ from typing import Any
5
+
6
+ from devagent_physical_engine.agent.compiler import AGENT_PLAN_SCHEMA
7
+ from devagent_physical_engine.agent.structured import CRITIQUE_SCHEMA, RECOVERY_SCHEMA
8
+ from devagent_physical_engine.engineering_request import ENGINEERING_REQUEST_SCHEMA
9
+ from devagent_physical_engine.provider_adapters.openai import _openai_strict_schema
10
+
11
+
12
+ class OpenAIStrictSchemaV0113Tests(unittest.TestCase):
13
+ def assert_strict_objects(self, value: Any) -> None:
14
+ if isinstance(value, list):
15
+ for item in value:
16
+ self.assert_strict_objects(item)
17
+ return
18
+ if not isinstance(value, dict):
19
+ return
20
+
21
+ properties = value.get("properties")
22
+ if isinstance(properties, dict):
23
+ self.assertEqual(set(value.get("required", [])), set(properties))
24
+ self.assertIs(value.get("additionalProperties"), False)
25
+
26
+ for child in value.values():
27
+ self.assert_strict_objects(child)
28
+
29
+ def test_all_live_agent_schemas_are_openai_strict_compatible(self):
30
+ for schema in (
31
+ ENGINEERING_REQUEST_SCHEMA,
32
+ AGENT_PLAN_SCHEMA,
33
+ CRITIQUE_SCHEMA,
34
+ RECOVERY_SCHEMA,
35
+ ):
36
+ with self.subTest(schema=id(schema)):
37
+ self.assert_strict_objects(_openai_strict_schema(schema))
38
+
39
+ def test_planner_optional_fields_become_required_nullable_transport_fields(self):
40
+ original_task = AGENT_PLAN_SCHEMA["properties"]["tasks"]["items"]
41
+ self.assertNotIn("depends_on", original_task["required"])
42
+
43
+ strict = _openai_strict_schema(AGENT_PLAN_SCHEMA)
44
+ task = strict["properties"]["tasks"]["items"]
45
+ self.assertEqual(set(task["required"]), set(task["properties"]))
46
+ self.assertIn("null", task["properties"]["depends_on"]["type"])
47
+ self.assertIn("null", task["properties"]["object_id"]["type"])
48
+ self.assertIn("null", task["properties"]["source"]["type"])
49
+ self.assertIn("null", task["properties"]["destination"]["type"])
50
+
51
+ # Provider-specific normalization must not mutate the provider-neutral core schema.
52
+ self.assertNotIn("depends_on", original_task["required"])
53
+ self.assertEqual(original_task["properties"]["depends_on"]["type"], "array")
54
+
55
+ def test_recovery_optional_retry_field_is_required_nullable_for_openai_only(self):
56
+ self.assertNotIn("retry_after_ms", RECOVERY_SCHEMA["required"])
57
+
58
+ strict = _openai_strict_schema(RECOVERY_SCHEMA)
59
+ self.assertIn("retry_after_ms", strict["required"])
60
+ retry_type = strict["properties"]["retry_after_ms"]["type"]
61
+ self.assertIn("integer", retry_type)
62
+ self.assertIn("null", retry_type)
63
+
64
+ self.assertNotIn("retry_after_ms", RECOVERY_SCHEMA["required"])
65
+
66
+
67
+ if __name__ == "__main__":
68
+ unittest.main()