devagent-physical-engine 0.11.3__tar.gz → 0.11.4__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.
- {devagent_physical_engine-0.11.3/src/devagent_physical_engine.egg-info → devagent_physical_engine-0.11.4}/PKG-INFO +23 -3
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/README.md +23 -3
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/pyproject.toml +1 -1
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/__init__.py +1 -1
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/coordinator.py +40 -1
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ai_cli.py +88 -7
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/engineering_agent.py +44 -1
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/provider_qualification.py +24 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4/src/devagent_physical_engine.egg-info}/PKG-INFO +23 -3
- devagent_physical_engine-0.11.4/tests/test_ai_cli.py +100 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_natural_language_agent_v07.py +21 -0
- devagent_physical_engine-0.11.3/tests/test_ai_cli.py +0 -54
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/NOTICE +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/setup.cfg +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/__init__.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/compiler.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/contracts.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/critic.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/evidence.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/interpreter.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/planner.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/recovery.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/routing.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/runtime.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/semantic.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/agent/structured.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/cli.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/continuous_clearance.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/doctor.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/engineering_request.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/execution.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/models.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/operating_envelope.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/__init__.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/benchmark.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/candidates.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/contracts.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/evaluator.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/evidence.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/experience.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/measured.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/optimizer.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/optimization/orchestrator.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/physical_campaign.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/physical_evidence.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/physical_motion.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/planning.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/preexecution_contract.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/provider_adapters/__init__.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/provider_adapters/anthropic.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/provider_adapters/common.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/provider_adapters/factory.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/provider_adapters/gemini.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/provider_adapters/openai.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/providers.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/qualification.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/qualification_cli.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/qualification_harness.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/robot_platform.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/robots.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/__init__.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/acceptance.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/commands.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/continuous_clearance_probe.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/doctor.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/fk_probe.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/frame_alignment.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/gazebo_world.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/joint_state_recorder.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/measured_motion.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/moveit_scene.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/preexecution.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/qualification.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/qualification_v10.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/qualification_v11.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/scene_probe.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/state_validity_probe.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/tf_probe.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/tool_scene.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/tool_scene_probe.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/trajectory.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/ur5e.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/ur5e_adapter.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/ur5e_v10_adapter.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/workpiece_scene.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/ros2/workpiece_scene_probe.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/setup_profile.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/sim_real_qualification.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/simulation.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/simulation_platform.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/tool_collision.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/trajectory_qualification.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/twin.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/twin_builder.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/twin_materialization.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/verification.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine/workpiece_lifecycle.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine.egg-info/SOURCES.txt +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine.egg-info/dependency_links.txt +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine.egg-info/entry_points.txt +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine.egg-info/requires.txt +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/src/devagent_physical_engine.egg-info/top_level.txt +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_agent_core.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_agent_semantic_hardening.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_ai_cli_v07.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_continuous_clearance_v011.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_core.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_engineering_request_v07.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_interpreter_profiles_v08.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_live_provider_qualification.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_measured_motion_v10.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_openai_strict_schema_v0113.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_optimization_v05.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_physical_campaign_v09.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_physical_evidence_v09.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_physical_motion_v09.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_preexecution_contract_v10.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_provider_and_qualification.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_qualification_cli_lifecycle_v06.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_qualification_harness_v06.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_real_provider_adapters.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_robot_platform_v08.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_ros2_production_receipts_v011.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_ros2_simulation.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_ros_trajectory_v09.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_setup_profile.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_sim_real_qualification_v011.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_simulation_platform_v08.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_tool_collision_v011.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_trajectory_qualification_v09.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_twin_materialization_v10.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_twin_v08.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_ur5e_adapter_scopes_v09.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_ur5e_v10_adapter_scopes.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_v052_stabilization.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/tests/test_v08_catalog_mapping_regression.py +0 -0
- {devagent_physical_engine-0.11.3 → devagent_physical_engine-0.11.4}/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.
|
|
3
|
+
Version: 0.11.4
|
|
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,11 +49,11 @@ DevAgent Smart Physical Engine adds AI-assisted engineering to existing automati
|
|
|
49
49
|
|
|
50
50
|
## Current version
|
|
51
51
|
|
|
52
|
-
**v0.11.
|
|
52
|
+
**v0.11.4 — 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
|
|
56
|
+
v0.11.3 normalized 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. v0.11.4 adds live terminal progress tracing for AI request, engineering, and provider-qualification workflows. Progress is written to `stderr`; final machine-readable JSON remains isolated on `stdout`.
|
|
57
57
|
|
|
58
58
|
Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
|
|
59
59
|
|
|
@@ -65,6 +65,7 @@ Real robot execution remains locked. Functional-safety certification and site qu
|
|
|
65
65
|
| OpenAI / Anthropic / Gemini structured adapters | Implemented |
|
|
66
66
|
| Planner / Critic / Recovery | Implemented |
|
|
67
67
|
| Natural-language engineering request front door | Implemented |
|
|
68
|
+
| Live terminal stage tracing (`stderr`) | Implemented; `--quiet` supported |
|
|
68
69
|
| Deterministic compiler / semantic / verification gates | Implemented |
|
|
69
70
|
| Multi-vendor robot profile registry | Implemented |
|
|
70
71
|
| UR5e / FANUC CRX / KUKA KR / ABB IRB abstraction | Implemented; physical qualification is vendor-specific |
|
|
@@ -210,6 +211,25 @@ devagent-physical-ai engineer \
|
|
|
210
211
|
--provider openai --model <model-id>
|
|
211
212
|
```
|
|
212
213
|
|
|
214
|
+
Live commands now show stage-by-stage progress while they are running, for example:
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
[DevAgent + 0.00s] START provider=openai model=<model-id>
|
|
218
|
+
[DevAgent + 0.00s] INTERPRETER understanding engineering request
|
|
219
|
+
[DevAgent + 6.84s] INTERPRETER validated request_id=REQ-...
|
|
220
|
+
[DevAgent + 6.84s] REASONING risk_score=1 max_revisions=1 critic_threshold=0.70
|
|
221
|
+
[DevAgent + 6.84s] PLANNER revision=0 generating high-level task graph
|
|
222
|
+
[DevAgent + 12.21s] PLANNER revision=0 proposal compiled and deterministically verified
|
|
223
|
+
[DevAgent + 12.21s] CRITIC revision=0 reviewing verified plan
|
|
224
|
+
[DevAgent + 15.77s] CRITIC revision=0 decision=accept score=0.91
|
|
225
|
+
[DevAgent + 15.77s] PLANNING verified plan accepted after revision=0
|
|
226
|
+
[DevAgent + 15.77s] SIMULATION running deterministic model execution
|
|
227
|
+
[DevAgent + 15.78s] SIMULATION deterministic model execution completed
|
|
228
|
+
[DevAgent + 15.78s] COMPLETE ready_for_twin_simulation=true
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Progress logs are emitted to `stderr`, so piping `stdout` still produces clean JSON. For CI or scripts that do not want terminal progress, add `--quiet`.
|
|
232
|
+
|
|
213
233
|
Equivalent routing supports Anthropic and Gemini. Live AI qualification does not unlock real robot execution.
|
|
214
234
|
|
|
215
235
|
## Software production gates
|
|
@@ -8,11 +8,11 @@ DevAgent Smart Physical Engine adds AI-assisted engineering to existing automati
|
|
|
8
8
|
|
|
9
9
|
## Current version
|
|
10
10
|
|
|
11
|
-
**v0.11.
|
|
11
|
+
**v0.11.4 — 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
|
|
15
|
+
v0.11.3 normalized 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. v0.11.4 adds live terminal progress tracing for AI request, engineering, and provider-qualification workflows. Progress is written to `stderr`; final machine-readable JSON remains isolated on `stdout`.
|
|
16
16
|
|
|
17
17
|
Real robot execution remains locked. Functional-safety certification and site qualification are not claimed.
|
|
18
18
|
|
|
@@ -24,6 +24,7 @@ Real robot execution remains locked. Functional-safety certification and site qu
|
|
|
24
24
|
| OpenAI / Anthropic / Gemini structured adapters | Implemented |
|
|
25
25
|
| Planner / Critic / Recovery | Implemented |
|
|
26
26
|
| Natural-language engineering request front door | Implemented |
|
|
27
|
+
| Live terminal stage tracing (`stderr`) | Implemented; `--quiet` supported |
|
|
27
28
|
| Deterministic compiler / semantic / verification gates | Implemented |
|
|
28
29
|
| Multi-vendor robot profile registry | Implemented |
|
|
29
30
|
| UR5e / FANUC CRX / KUKA KR / ABB IRB abstraction | Implemented; physical qualification is vendor-specific |
|
|
@@ -169,6 +170,25 @@ devagent-physical-ai engineer \
|
|
|
169
170
|
--provider openai --model <model-id>
|
|
170
171
|
```
|
|
171
172
|
|
|
173
|
+
Live commands now show stage-by-stage progress while they are running, for example:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
[DevAgent + 0.00s] START provider=openai model=<model-id>
|
|
177
|
+
[DevAgent + 0.00s] INTERPRETER understanding engineering request
|
|
178
|
+
[DevAgent + 6.84s] INTERPRETER validated request_id=REQ-...
|
|
179
|
+
[DevAgent + 6.84s] REASONING risk_score=1 max_revisions=1 critic_threshold=0.70
|
|
180
|
+
[DevAgent + 6.84s] PLANNER revision=0 generating high-level task graph
|
|
181
|
+
[DevAgent + 12.21s] PLANNER revision=0 proposal compiled and deterministically verified
|
|
182
|
+
[DevAgent + 12.21s] CRITIC revision=0 reviewing verified plan
|
|
183
|
+
[DevAgent + 15.77s] CRITIC revision=0 decision=accept score=0.91
|
|
184
|
+
[DevAgent + 15.77s] PLANNING verified plan accepted after revision=0
|
|
185
|
+
[DevAgent + 15.77s] SIMULATION running deterministic model execution
|
|
186
|
+
[DevAgent + 15.78s] SIMULATION deterministic model execution completed
|
|
187
|
+
[DevAgent + 15.78s] COMPLETE ready_for_twin_simulation=true
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Progress logs are emitted to `stderr`, so piping `stdout` still produces clean JSON. For CI or scripts that do not want terminal progress, add `--quiet`.
|
|
191
|
+
|
|
172
192
|
Equivalent routing supports Anthropic and Gemini. Live AI qualification does not unlock real robot execution.
|
|
173
193
|
|
|
174
194
|
## Software production gates
|
|
@@ -294,4 +314,4 @@ DevAgent Smart Physical Engine
|
|
|
294
314
|
Copyright © 2026 Tom Ha
|
|
295
315
|
Original creator: Tom Ha
|
|
296
316
|
Original project: https://github.com/tomha85/devagent-physical-engine
|
|
297
|
-
All rights reserved.
|
|
317
|
+
All rights reserved.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "devagent-physical-engine"
|
|
7
|
-
version = "0.11.
|
|
7
|
+
version = "0.11.4"
|
|
8
8
|
description = "Verification-first agentic planning runtime for robotic and industrial automation."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, Mapping
|
|
4
|
+
from typing import Any, Callable, Mapping
|
|
5
5
|
|
|
6
6
|
from .contracts import AgentEvidence, CriticDecision, RoutingPolicy
|
|
7
7
|
from .critic import CriticAgent
|
|
@@ -9,6 +9,8 @@ from .evidence import task_graph_hash
|
|
|
9
9
|
from .planner import PlannerAgent
|
|
10
10
|
from ..models import Goal, Resource, TaskGraph, WorldState
|
|
11
11
|
|
|
12
|
+
ProgressCallback = Callable[[str, str], None]
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
class PlanningCoordinationError(RuntimeError):
|
|
14
16
|
pass
|
|
@@ -52,12 +54,18 @@ class PlanningCoordinator:
|
|
|
52
54
|
critic_policy: RoutingPolicy,
|
|
53
55
|
*,
|
|
54
56
|
engineering_context: Mapping[str, Any] | None = None,
|
|
57
|
+
progress: ProgressCallback | None = None,
|
|
55
58
|
) -> VerifiedPlanArtifact:
|
|
56
59
|
feedback: tuple[str, ...] = ()
|
|
57
60
|
planner_evidence: list[AgentEvidence] = []
|
|
58
61
|
critic_evidence: list[AgentEvidence] = []
|
|
59
62
|
|
|
60
63
|
for revision in range(self.max_revision_rounds + 1):
|
|
64
|
+
if progress is not None:
|
|
65
|
+
progress(
|
|
66
|
+
"PLANNER",
|
|
67
|
+
f"revision={revision} generating high-level task graph",
|
|
68
|
+
)
|
|
61
69
|
planned = self.planner.plan(
|
|
62
70
|
goal,
|
|
63
71
|
resources,
|
|
@@ -67,6 +75,15 @@ class PlanningCoordinator:
|
|
|
67
75
|
engineering_context=engineering_context,
|
|
68
76
|
)
|
|
69
77
|
planner_evidence.append(planned.evidence)
|
|
78
|
+
if progress is not None:
|
|
79
|
+
progress(
|
|
80
|
+
"PLANNER",
|
|
81
|
+
f"revision={revision} proposal compiled and deterministically verified",
|
|
82
|
+
)
|
|
83
|
+
progress(
|
|
84
|
+
"CRITIC",
|
|
85
|
+
f"revision={revision} reviewing verified plan",
|
|
86
|
+
)
|
|
70
87
|
|
|
71
88
|
reviewed = self.critic.review(
|
|
72
89
|
goal,
|
|
@@ -77,11 +94,24 @@ class PlanningCoordinator:
|
|
|
77
94
|
engineering_context=engineering_context,
|
|
78
95
|
)
|
|
79
96
|
critic_evidence.append(reviewed.evidence)
|
|
97
|
+
if progress is not None:
|
|
98
|
+
progress(
|
|
99
|
+
"CRITIC",
|
|
100
|
+
(
|
|
101
|
+
f"revision={revision} decision={reviewed.critique.decision.value} "
|
|
102
|
+
f"score={reviewed.critique.score:.2f}"
|
|
103
|
+
),
|
|
104
|
+
)
|
|
80
105
|
|
|
81
106
|
if (
|
|
82
107
|
reviewed.critique.decision is CriticDecision.ACCEPT
|
|
83
108
|
and reviewed.critique.score >= self.min_accept_score
|
|
84
109
|
):
|
|
110
|
+
if progress is not None:
|
|
111
|
+
progress(
|
|
112
|
+
"PLANNING",
|
|
113
|
+
f"verified plan accepted after revision={revision}",
|
|
114
|
+
)
|
|
85
115
|
return VerifiedPlanArtifact(
|
|
86
116
|
graph=planned.graph,
|
|
87
117
|
graph_hash=task_graph_hash(planned.graph),
|
|
@@ -91,6 +121,8 @@ class PlanningCoordinator:
|
|
|
91
121
|
)
|
|
92
122
|
|
|
93
123
|
if reviewed.critique.decision is CriticDecision.REJECT:
|
|
124
|
+
if progress is not None:
|
|
125
|
+
progress("PLANNING", f"critic rejected revision={revision}")
|
|
94
126
|
raise PlanningCoordinationError(
|
|
95
127
|
"critic_rejected_plan:"
|
|
96
128
|
+ ";".join(reviewed.critique.issues)
|
|
@@ -104,5 +136,12 @@ class PlanningCoordinator:
|
|
|
104
136
|
feedback = reviewed.critique.issues or (
|
|
105
137
|
"critic_requested_revision",
|
|
106
138
|
)
|
|
139
|
+
if progress is not None:
|
|
140
|
+
progress(
|
|
141
|
+
"PLANNING",
|
|
142
|
+
f"revision={revision} requires another planning round",
|
|
143
|
+
)
|
|
107
144
|
|
|
145
|
+
if progress is not None:
|
|
146
|
+
progress("PLANNING", "revision budget exhausted")
|
|
108
147
|
raise PlanningCoordinationError("revision_budget_exhausted")
|
|
@@ -4,6 +4,9 @@ import argparse
|
|
|
4
4
|
import importlib.util
|
|
5
5
|
import json
|
|
6
6
|
import os
|
|
7
|
+
import sys
|
|
8
|
+
import time
|
|
9
|
+
from collections.abc import Callable
|
|
7
10
|
|
|
8
11
|
from .agent import (
|
|
9
12
|
AgentRuntime,
|
|
@@ -20,6 +23,8 @@ from .provider_adapters import PROVIDER_NAMES, create_provider
|
|
|
20
23
|
from .provider_qualification import qualify_live_provider
|
|
21
24
|
from .providers import ModelRegistry, ModelSpec, QualificationStatus
|
|
22
25
|
|
|
26
|
+
ProgressCallback = Callable[[str, str], None]
|
|
27
|
+
|
|
23
28
|
|
|
24
29
|
def _add_live_request_args(parser: argparse.ArgumentParser) -> None:
|
|
25
30
|
parser.add_argument("text", help="Natural-language engineering request")
|
|
@@ -33,6 +38,11 @@ def _add_live_request_args(parser: argparse.ArgumentParser) -> None:
|
|
|
33
38
|
)
|
|
34
39
|
parser.add_argument("--timeout", type=float, default=30.0)
|
|
35
40
|
parser.add_argument("--max-attempts", type=int, default=2)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--quiet",
|
|
43
|
+
action="store_true",
|
|
44
|
+
help="Suppress terminal progress logs; final JSON remains on stdout",
|
|
45
|
+
)
|
|
36
46
|
|
|
37
47
|
|
|
38
48
|
def _parser() -> argparse.ArgumentParser:
|
|
@@ -54,6 +64,11 @@ def _parser() -> argparse.ArgumentParser:
|
|
|
54
64
|
qualify.add_argument("--timeout", type=float, default=30.0)
|
|
55
65
|
qualify.add_argument("--max-attempts", type=int, default=2)
|
|
56
66
|
qualify.add_argument("--max-revisions", type=int, default=2)
|
|
67
|
+
qualify.add_argument(
|
|
68
|
+
"--quiet",
|
|
69
|
+
action="store_true",
|
|
70
|
+
help="Suppress terminal progress logs; final JSON remains on stdout",
|
|
71
|
+
)
|
|
57
72
|
|
|
58
73
|
request = sub.add_parser(
|
|
59
74
|
"request",
|
|
@@ -93,6 +108,28 @@ def provider_doctor(provider: str) -> dict:
|
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
|
|
111
|
+
def _terminal_progress(enabled: bool) -> ProgressCallback | None:
|
|
112
|
+
if not enabled:
|
|
113
|
+
return None
|
|
114
|
+
started = time.monotonic()
|
|
115
|
+
|
|
116
|
+
def emit(stage: str, message: str) -> None:
|
|
117
|
+
elapsed = time.monotonic() - started
|
|
118
|
+
label = stage.strip().upper()[:12]
|
|
119
|
+
print(
|
|
120
|
+
f"[DevAgent +{elapsed:7.2f}s] {label:<12} {message}",
|
|
121
|
+
file=sys.stderr,
|
|
122
|
+
flush=True,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
return emit
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _emit(progress: ProgressCallback | None, stage: str, message: str) -> None:
|
|
129
|
+
if progress is not None:
|
|
130
|
+
progress(stage, message)
|
|
131
|
+
|
|
132
|
+
|
|
96
133
|
def _live_runtime(provider_name: str, model: str, *, timeout: float, max_attempts: int):
|
|
97
134
|
provider = create_provider(provider_name)
|
|
98
135
|
registry = ModelRegistry()
|
|
@@ -123,30 +160,51 @@ def _live_runtime(provider_name: str, model: str, *, timeout: float, max_attempt
|
|
|
123
160
|
return provider, runtime, policy
|
|
124
161
|
|
|
125
162
|
|
|
126
|
-
def _request(args: argparse.Namespace) -> int:
|
|
163
|
+
def _request(args: argparse.Namespace, progress: ProgressCallback | None = None) -> int:
|
|
164
|
+
_emit(progress, "START", f"provider={args.provider} model={args.model}")
|
|
127
165
|
_, runtime, policy = _live_runtime(
|
|
128
166
|
args.provider,
|
|
129
167
|
args.model,
|
|
130
168
|
timeout=args.timeout,
|
|
131
169
|
max_attempts=args.max_attempts,
|
|
132
170
|
)
|
|
171
|
+
_emit(progress, "INTERPRETER", "understanding engineering request")
|
|
133
172
|
interpreted = RequirementInterpreterAgent(runtime).interpret(
|
|
134
173
|
args.text,
|
|
135
174
|
policy,
|
|
136
175
|
follow_ups=args.follow_up,
|
|
137
176
|
)
|
|
177
|
+
if interpreted.validated is not None:
|
|
178
|
+
_emit(
|
|
179
|
+
progress,
|
|
180
|
+
"INTERPRETER",
|
|
181
|
+
f"validated request_id={interpreted.validated.request_id}",
|
|
182
|
+
)
|
|
183
|
+
elif interpreted.rejection_code:
|
|
184
|
+
_emit(
|
|
185
|
+
progress,
|
|
186
|
+
"INTERPRETER",
|
|
187
|
+
f"request rejected code={interpreted.rejection_code}",
|
|
188
|
+
)
|
|
189
|
+
else:
|
|
190
|
+
_emit(progress, "INTERPRETER", "more engineering information required")
|
|
191
|
+
|
|
138
192
|
payload = interpreted.to_dict()
|
|
139
193
|
payload["provider_mode"] = "simulation_only_ephemeral_route"
|
|
140
194
|
payload["real_execution_allowed"] = False
|
|
141
195
|
print(json.dumps(payload, indent=2))
|
|
142
196
|
if interpreted.validated is not None:
|
|
197
|
+
_emit(progress, "COMPLETE", "request validation passed")
|
|
143
198
|
return 0
|
|
144
199
|
if interpreted.rejection_code:
|
|
200
|
+
_emit(progress, "COMPLETE", "request validation rejected")
|
|
145
201
|
return 4
|
|
202
|
+
_emit(progress, "COMPLETE", "request requires follow-up information")
|
|
146
203
|
return 3
|
|
147
204
|
|
|
148
205
|
|
|
149
|
-
def _engineer(args: argparse.Namespace) -> int:
|
|
206
|
+
def _engineer(args: argparse.Namespace, progress: ProgressCallback | None = None) -> int:
|
|
207
|
+
_emit(progress, "START", f"provider={args.provider} model={args.model}")
|
|
150
208
|
_, runtime, policy = _live_runtime(
|
|
151
209
|
args.provider,
|
|
152
210
|
args.model,
|
|
@@ -164,6 +222,7 @@ def _engineer(args: argparse.Namespace) -> int:
|
|
|
164
222
|
planner_policy=policy,
|
|
165
223
|
critic_policy=policy,
|
|
166
224
|
follow_ups=args.follow_up,
|
|
225
|
+
progress=progress,
|
|
167
226
|
)
|
|
168
227
|
payload = result.to_dict()
|
|
169
228
|
payload["provider_mode"] = "simulation_only_ephemeral_route"
|
|
@@ -171,12 +230,25 @@ def _engineer(args: argparse.Namespace) -> int:
|
|
|
171
230
|
print(json.dumps(payload, indent=2))
|
|
172
231
|
if result.ready_for_twin_simulation:
|
|
173
232
|
return 0
|
|
233
|
+
_emit(
|
|
234
|
+
progress,
|
|
235
|
+
"COMPLETE",
|
|
236
|
+
(
|
|
237
|
+
"ready_for_twin_simulation=false "
|
|
238
|
+
f"failure_code={result.failure_code or 'more_information_required'}"
|
|
239
|
+
),
|
|
240
|
+
)
|
|
174
241
|
if result.interpretation.validated is None and not result.interpretation.rejection_code:
|
|
175
242
|
return 3
|
|
176
243
|
return 4
|
|
177
244
|
|
|
178
245
|
|
|
179
|
-
def _natural_language_failure(
|
|
246
|
+
def _natural_language_failure(
|
|
247
|
+
exc: BaseException,
|
|
248
|
+
*,
|
|
249
|
+
progress: ProgressCallback | None = None,
|
|
250
|
+
) -> int:
|
|
251
|
+
_emit(progress, "FAILED", f"pipeline stopped type={type(exc).__name__}")
|
|
180
252
|
print(
|
|
181
253
|
json.dumps(
|
|
182
254
|
{
|
|
@@ -198,18 +270,21 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
198
270
|
print(json.dumps(result, indent=2))
|
|
199
271
|
return 0 if result["ready_for_live_qualification"] else 1
|
|
200
272
|
|
|
273
|
+
progress = _terminal_progress(not getattr(args, "quiet", False))
|
|
274
|
+
|
|
201
275
|
if args.command == "request":
|
|
202
276
|
try:
|
|
203
|
-
return _request(args)
|
|
277
|
+
return _request(args, progress)
|
|
204
278
|
except Exception as exc:
|
|
205
|
-
return _natural_language_failure(exc)
|
|
279
|
+
return _natural_language_failure(exc, progress=progress)
|
|
206
280
|
|
|
207
281
|
if args.command == "engineer":
|
|
208
282
|
try:
|
|
209
|
-
return _engineer(args)
|
|
283
|
+
return _engineer(args, progress)
|
|
210
284
|
except Exception as exc:
|
|
211
|
-
return _natural_language_failure(exc)
|
|
285
|
+
return _natural_language_failure(exc, progress=progress)
|
|
212
286
|
|
|
287
|
+
_emit(progress, "START", f"provider={args.provider} model={args.model}")
|
|
213
288
|
provider = create_provider(args.provider)
|
|
214
289
|
report = qualify_live_provider(
|
|
215
290
|
provider,
|
|
@@ -217,6 +292,12 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
217
292
|
timeout_s=args.timeout,
|
|
218
293
|
max_attempts=args.max_attempts,
|
|
219
294
|
max_revision_rounds=args.max_revisions,
|
|
295
|
+
progress=progress,
|
|
296
|
+
)
|
|
297
|
+
_emit(
|
|
298
|
+
progress,
|
|
299
|
+
"RESULT",
|
|
300
|
+
f"passed={str(report.passed).lower()} failure_code={report.failure_code or 'none'}",
|
|
220
301
|
)
|
|
221
302
|
print(json.dumps(report.to_dict(), indent=2))
|
|
222
303
|
return 0 if report.passed else 2
|
|
@@ -4,7 +4,12 @@ from dataclasses import asdict, dataclass
|
|
|
4
4
|
from typing import Any, Sequence
|
|
5
5
|
|
|
6
6
|
from .agent.contracts import AgentEvidence, RoutingPolicy
|
|
7
|
-
from .agent.coordinator import
|
|
7
|
+
from .agent.coordinator import (
|
|
8
|
+
PlanningCoordinationError,
|
|
9
|
+
PlanningCoordinator,
|
|
10
|
+
ProgressCallback,
|
|
11
|
+
VerifiedPlanArtifact,
|
|
12
|
+
)
|
|
8
13
|
from .agent.critic import CriticAgent
|
|
9
14
|
from .agent.evidence import task_graph_to_dict
|
|
10
15
|
from .agent.interpreter import InterpretedEngineeringRequest, RequirementInterpreterAgent
|
|
@@ -153,7 +158,10 @@ class SmartEngineeringAgent:
|
|
|
153
158
|
planner_policy: RoutingPolicy,
|
|
154
159
|
critic_policy: RoutingPolicy,
|
|
155
160
|
follow_ups: Sequence[str] = (),
|
|
161
|
+
progress: ProgressCallback | None = None,
|
|
156
162
|
) -> SmartEngineeringResult:
|
|
163
|
+
if progress is not None:
|
|
164
|
+
progress("INTERPRETER", "understanding engineering request")
|
|
157
165
|
interpreted = self.interpreter.interpret(
|
|
158
166
|
text,
|
|
159
167
|
interpreter_policy,
|
|
@@ -161,12 +169,32 @@ class SmartEngineeringAgent:
|
|
|
161
169
|
)
|
|
162
170
|
request = interpreted.validated
|
|
163
171
|
if request is None:
|
|
172
|
+
if progress is not None:
|
|
173
|
+
if interpreted.rejection_code:
|
|
174
|
+
progress(
|
|
175
|
+
"INTERPRETER",
|
|
176
|
+
f"request rejected code={interpreted.rejection_code}",
|
|
177
|
+
)
|
|
178
|
+
else:
|
|
179
|
+
progress("INTERPRETER", "more engineering information required")
|
|
164
180
|
return SmartEngineeringResult(
|
|
165
181
|
interpretation=interpreted,
|
|
166
182
|
failure_code=interpreted.rejection_code,
|
|
167
183
|
)
|
|
168
184
|
|
|
185
|
+
if progress is not None:
|
|
186
|
+
progress("INTERPRETER", f"validated request_id={request.request_id}")
|
|
187
|
+
|
|
169
188
|
strategy = self.reasoning_policy.select(request)
|
|
189
|
+
if progress is not None:
|
|
190
|
+
progress(
|
|
191
|
+
"REASONING",
|
|
192
|
+
(
|
|
193
|
+
f"risk_score={strategy.risk_score} "
|
|
194
|
+
f"max_revisions={strategy.max_revision_rounds} "
|
|
195
|
+
f"critic_threshold={strategy.min_critic_score:.2f}"
|
|
196
|
+
),
|
|
197
|
+
)
|
|
170
198
|
goal = request.goal()
|
|
171
199
|
resources = [request.resource()]
|
|
172
200
|
# Explicit nominal model state, never represented as observed site state.
|
|
@@ -191,14 +219,19 @@ class SmartEngineeringAgent:
|
|
|
191
219
|
planner_policy,
|
|
192
220
|
critic_policy,
|
|
193
221
|
engineering_context=request.to_dict(),
|
|
222
|
+
progress=progress,
|
|
194
223
|
)
|
|
195
224
|
except PlanningCoordinationError as exc:
|
|
225
|
+
if progress is not None:
|
|
226
|
+
progress("PLANNING", "planning coordination failed")
|
|
196
227
|
return SmartEngineeringResult(
|
|
197
228
|
interpretation=interpreted,
|
|
198
229
|
reasoning_strategy=strategy,
|
|
199
230
|
failure_code=f"planning_failed:{str(exc).split(':', 1)[0]}",
|
|
200
231
|
)
|
|
201
232
|
except Exception as exc:
|
|
233
|
+
if progress is not None:
|
|
234
|
+
progress("PLANNING", f"planning failed type={type(exc).__name__}")
|
|
202
235
|
# Never expose provider/internal exception text as customer evidence.
|
|
203
236
|
return SmartEngineeringResult(
|
|
204
237
|
interpretation=interpreted,
|
|
@@ -206,6 +239,8 @@ class SmartEngineeringAgent:
|
|
|
206
239
|
failure_code=f"planning_failed:{type(exc).__name__}",
|
|
207
240
|
)
|
|
208
241
|
|
|
242
|
+
if progress is not None:
|
|
243
|
+
progress("SIMULATION", "running deterministic model execution")
|
|
209
244
|
simulation_world = WorldState(facts=set(world.facts), values=dict(world.values))
|
|
210
245
|
simulation = ExecutionSupervisor().execute(
|
|
211
246
|
plan.graph,
|
|
@@ -216,6 +251,11 @@ class SmartEngineeringAgent:
|
|
|
216
251
|
)
|
|
217
252
|
if not simulation.completed:
|
|
218
253
|
issue_codes = sorted({issue.code for issue in simulation.issues})
|
|
254
|
+
if progress is not None:
|
|
255
|
+
progress(
|
|
256
|
+
"SIMULATION",
|
|
257
|
+
"blocked by deterministic constraints",
|
|
258
|
+
)
|
|
219
259
|
return SmartEngineeringResult(
|
|
220
260
|
interpretation=interpreted,
|
|
221
261
|
reasoning_strategy=strategy,
|
|
@@ -227,6 +267,9 @@ class SmartEngineeringAgent:
|
|
|
227
267
|
),
|
|
228
268
|
)
|
|
229
269
|
|
|
270
|
+
if progress is not None:
|
|
271
|
+
progress("SIMULATION", "deterministic model execution completed")
|
|
272
|
+
progress("COMPLETE", "ready_for_twin_simulation=true")
|
|
230
273
|
return SmartEngineeringResult(
|
|
231
274
|
interpretation=interpreted,
|
|
232
275
|
reasoning_strategy=strategy,
|
|
@@ -15,6 +15,7 @@ from .agent import (
|
|
|
15
15
|
RoutingPolicy,
|
|
16
16
|
RoutingStrategy,
|
|
17
17
|
)
|
|
18
|
+
from .agent.coordinator import ProgressCallback
|
|
18
19
|
from .agent.runtime import AgentRuntimeError
|
|
19
20
|
from .execution import ExecutionMode, ExecutionSupervisor
|
|
20
21
|
from .models import WorldState
|
|
@@ -97,6 +98,7 @@ def qualify_live_provider(
|
|
|
97
98
|
timeout_s: float = 30.0,
|
|
98
99
|
max_attempts: int = 2,
|
|
99
100
|
max_revision_rounds: int = 2,
|
|
101
|
+
progress: ProgressCallback | None = None,
|
|
100
102
|
) -> LiveProviderQualificationReport:
|
|
101
103
|
"""Run Interpreter -> Planner -> Critic -> verify/simulate -> Recovery.
|
|
102
104
|
|
|
@@ -140,12 +142,16 @@ def qualify_live_provider(
|
|
|
140
142
|
request_validated = False
|
|
141
143
|
|
|
142
144
|
try:
|
|
145
|
+
if progress is not None:
|
|
146
|
+
progress("INTERPRETER", "running qualification request interpretation")
|
|
143
147
|
interpreted = RequirementInterpreterAgent(runtime).interpret(
|
|
144
148
|
"Use the UR5e to load P17 from conveyor_a into cnc_04. Simulate the operation using an engineering test preset.",
|
|
145
149
|
policy,
|
|
146
150
|
)
|
|
147
151
|
evidence.append(interpreted.evidence)
|
|
148
152
|
if interpreted.validated is None:
|
|
153
|
+
if progress is not None:
|
|
154
|
+
progress("INTERPRETER", "qualification request was not validated")
|
|
149
155
|
request_ids = _request_ids(evidence)
|
|
150
156
|
input_tokens, output_tokens, total_tokens = _usage(provider, request_ids)
|
|
151
157
|
return LiveProviderQualificationReport(
|
|
@@ -169,6 +175,8 @@ def qualify_live_provider(
|
|
|
169
175
|
|
|
170
176
|
request_validated = True
|
|
171
177
|
request = interpreted.validated
|
|
178
|
+
if progress is not None:
|
|
179
|
+
progress("INTERPRETER", f"validated request_id={request.request_id}")
|
|
172
180
|
goal = request.goal()
|
|
173
181
|
robot = request.resource()
|
|
174
182
|
|
|
@@ -189,10 +197,13 @@ def qualify_live_provider(
|
|
|
189
197
|
policy,
|
|
190
198
|
policy,
|
|
191
199
|
engineering_context=request.to_dict(),
|
|
200
|
+
progress=progress,
|
|
192
201
|
)
|
|
193
202
|
evidence.extend(artifact.planner_evidence)
|
|
194
203
|
evidence.extend(artifact.critic_evidence)
|
|
195
204
|
|
|
205
|
+
if progress is not None:
|
|
206
|
+
progress("SIMULATION", "running deterministic qualification simulation")
|
|
196
207
|
simulation_world = WorldState(facts=set(world.facts), values=dict(world.values))
|
|
197
208
|
simulation = ExecutionSupervisor().execute(
|
|
198
209
|
artifact.graph,
|
|
@@ -202,6 +213,8 @@ def qualify_live_provider(
|
|
|
202
213
|
ExecutionMode.SIMULATION,
|
|
203
214
|
)
|
|
204
215
|
if not simulation.completed:
|
|
216
|
+
if progress is not None:
|
|
217
|
+
progress("SIMULATION", "deterministic qualification simulation failed")
|
|
205
218
|
request_ids = _request_ids(evidence)
|
|
206
219
|
input_tokens, output_tokens, total_tokens = _usage(provider, request_ids)
|
|
207
220
|
return LiveProviderQualificationReport(
|
|
@@ -220,6 +233,9 @@ def qualify_live_provider(
|
|
|
220
233
|
total_tokens=total_tokens,
|
|
221
234
|
failure_code="deterministic_simulation_failed",
|
|
222
235
|
)
|
|
236
|
+
if progress is not None:
|
|
237
|
+
progress("SIMULATION", "deterministic qualification simulation completed")
|
|
238
|
+
progress("RECOVERY", "checking bounded recovery advice")
|
|
223
239
|
|
|
224
240
|
recovered = recovery.advise(
|
|
225
241
|
task_id="T2",
|
|
@@ -228,6 +244,12 @@ def qualify_live_provider(
|
|
|
228
244
|
policy=policy,
|
|
229
245
|
)
|
|
230
246
|
evidence.append(recovered.evidence)
|
|
247
|
+
if progress is not None:
|
|
248
|
+
progress(
|
|
249
|
+
"RECOVERY",
|
|
250
|
+
f"decision={recovered.advice.decision.value}",
|
|
251
|
+
)
|
|
252
|
+
progress("COMPLETE", "live provider qualification passed")
|
|
231
253
|
request_ids = _request_ids(evidence)
|
|
232
254
|
input_tokens, output_tokens, total_tokens = _usage(provider, request_ids)
|
|
233
255
|
return LiveProviderQualificationReport(
|
|
@@ -247,6 +269,8 @@ def qualify_live_provider(
|
|
|
247
269
|
failure_code=None,
|
|
248
270
|
)
|
|
249
271
|
except Exception as exc:
|
|
272
|
+
if progress is not None:
|
|
273
|
+
progress("FAILED", f"qualification stopped type={type(exc).__name__}")
|
|
250
274
|
_append_exception_evidence(evidence, exc)
|
|
251
275
|
request_ids = _request_ids(evidence)
|
|
252
276
|
input_tokens, output_tokens, total_tokens = _usage(provider, request_ids)
|