Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .agents/skills/add-atomic-action/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,16 @@ Follow these invariants:

## 4. Emit generic runtime commands when needed

For a joint-backed Skill that must also consume external or augmented motion,
declare a versioned `SkillTrajectoryContract` and implement
`_trajectory_semantics(request, context, motion) -> SkillPlanSemantics`. Call the
framework-owned `assemble_trajectory_plan()` from ordinary `_plan()` after
generating a `SkillTrajectoryInput`; external callers use the engine's
`build_plan_from_trajectory()`. Reuse the same semantic hook instead of adding
recording-specific methods. Keep file decoding/calibration in source adapters
and expansion permissions in the motion-expansion layer. See PickUp and
MoveJoints for typed geometry, event landmarks and goal checks.

Use `build_command_plan()` when a skill targets a mobile base, whole-body
controller, tool, or another non-joint transport. Build immutable endpoint
commands; keep live controller and device handles in the transport:
Expand Down
10 changes: 6 additions & 4 deletions agent_context/MAP.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ topics:
via_points, nullspace_residual, perturb_approach_direction, sample_approach_cone, TIMING_PROFILES,
trajectory variant, 轨迹变体, 固定路点,
collision world, compute trajectory, trajectory resampling, trajectory warping, retime_to_control_grid,
JointTrajectoryPlaybackCfg, play_joint_trajectory, quaternion, xyzw, wxyz]
JointTrajectoryPlaybackCfg, play_joint_trajectory, Real2SimSourceAdapter, AnchoredTimeMap, quaternion, xyzw, wxyz]
paths: [topics/motion-planning/motion-planning.md]
source_of_truth:
- embodichain/lab/sim/motion/planners/base_planner.py
Expand Down Expand Up @@ -313,13 +313,14 @@ topics:
- id: atomic-actions
title: Atomic Skills
aliases: [atomic action, atomic skill, 原子动作, 原子技能]
keywords: [AtomicActionEngine, run-atomic-action, PlanningContext, ExecutionSession, ExecutionRunner, ActionInvocation,
keywords: [AtomicActionEngine, NominalPlanProvider, SkillTrajectoryInput, SkillTrajectoryContract, SkillPlanSemantics, run-atomic-action, PlanningContext, ExecutionSession, ExecutionRunner, ActionInvocation,
RecoveryPolicy, HeldObjectGuardRequest, PhaseEffectGateRequest, articulation_geometry, control-grid retiming,
AffordanceSamplingContext, AffordancePoseCandidates, AffordanceSample, affordance sampling]
paths: [topics/atomic-actions/atomic-actions.md]
source_of_truth:
- embodichain/lab/sim/atomic_actions/engine.py
- embodichain/lab/sim/atomic_actions/core.py
- embodichain/lab/sim/atomic_actions/trajectory_assembly.py
- embodichain/lab/sim/atomic_actions/goals.py
- embodichain/lab/sim/atomic_actions/execution.py
- embodichain/lab/sim/atomic_actions/verification.py
Expand All @@ -339,7 +340,8 @@ topics:
keywords: [TaskProgramCfg, program.yaml, integration.yaml, scene_binding, SceneManifest, SkillPolicyPreset,
EffectAssurance, CompiledTaskProgram, TaskProgramDemoBridge, TaskProgramPlanTransformFactory,
CombinedTaskProgramExpansionFactory, expansion_profile, execution_policy, SemanticPose, quaternion_xyzw,
joint_command_mode]
joint_command_mode, TaskProgramNominalPlanFactory, ExpertSourceProviderFactory, ExpertSourceRegistry,
Real2SimExpertSourceProviderFactory]
paths: [topics/task-programs/task-programs.md]
source_of_truth:
- embodichain/lab/task_program/
Expand Down Expand Up @@ -393,7 +395,7 @@ topics:
keywords: [OnlineDataEngine, OnlineDataset, sample_batch, lock_index, LeRobotRecorder, AsyncLeRobotRecorder,
DepthSidecarManager, depth_meta.json, fragment_id, finalize, expert action schema, qpos_slice, qvel_slice,
validate_dataset, create_split_manifest, recover_recording, episode_uuid, language_persistent,
SharedLanguageRegistry, resolve_language]
SharedLanguageRegistry, resolve_language, Real2SimTrajectory, normalize_real2sim, 真实轨迹归一化]
paths: [topics/data-pipeline/data-pipeline.md]
source_of_truth:
- embodichain/data_pipeline/engine/data.py
Expand Down
20 changes: 20 additions & 0 deletions agent_context/topics/atomic-actions/atomic-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ ActionInvocation semantic program
EndpointCommandRouter + transports + clock
```

`NominalPlanProvider` is an optional trusted complete-plan source on engine
planning/start calls. It bypasses ordinary action planning without bypassing
plan validation, and remains attached to the execution session for replans and
invocation revisions. Existing transforms run after nominal validation. A
replay-only source must return a non-replannable plan; the hook does not itself
supply Skill-specific semantic assembly or certify source capabilities.

Planning never steps simulation and never treats command completion as proof of
a physical effect.

Expand All @@ -69,6 +76,7 @@ contact or physical goal satisfaction.
| Invocation, binding, and policies | `invocation.py`, `bindings.py`, `policies.py`, `control.py` |
| Robot/task/scene state | `state.py`, `scene.py` |
| Plans and runtime commands | `plans.py`, `runtime_commands.py` |
| Source-neutral trajectory inputs, schema and Skill semantic assembly | `trajectory_assembly.py`, `core.py` |
| Session state machine | `execution.py` |
| Verification request/result values | `verification.py` |
| Runner and transports | `runner.py`, `transports.py`, `tracking.py` |
Expand Down Expand Up @@ -203,3 +211,15 @@ python docs/scripts/check_api_docs.py
For public API changes also run the docs checker tests and Sphinx dummy build.
For simulator adapters add an environment-level test that exercises normal
`env.step()` consumption and safe cancellation.

`AtomicActionEngine.build_plan_from_trajectory` admits full-joint motion through
an explicit versioned `SkillDescriptor.trajectory_contract`, then delegates to
the framework-owned `AtomicAction.assemble_trajectory_plan`. PickUp and
MoveJoints share their `_trajectory_semantics` hook between ordinary planning
and external motion; other Skills opt in explicitly. Skill code owns effects
and geometric facts, while the public builder owns commands and tracking.
`ActionPlan.trajectory_input` retains an owned input for same-grid rebuilding;
rebuilding reassembles semantics and rejects stale geometric-event facts.
Semantic stages/events do not grant expansion permissions. Input source/model
review remains provider-owned, and fixed replay remains non-replannable.
See [trajectory assembly details](execution.md#trajectory-backed-plan-assembly).
22 changes: 22 additions & 0 deletions agent_context/topics/atomic-actions/execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,25 @@ it never substitutes observed velocities or depends on peer active masks.
It writes position and velocity targets through the existing `set_qpos` and
`set_qvel` APIs. Inactive rows hold observed positions with zero target velocity.
A nonzero damping gain is needed for the velocity error to contribute to tracking.

## Trajectory-backed plan assembly

`trajectory_assembly.py` owns immutable Skill schemas, timed inputs and semantic
assembly results. A concrete Skill opts in through `trajectory_contract` and
implements `_trajectory_semantics`; it does not override the public assembler.
The schema participates in the existing semantic catalog fingerprint. Registration
rejects a declared contract without an assembler, and unsupported Skills fail
before ordinary planning rather than falling back.

The engine checks imported motion against restored initial state, position and
sampled/interval velocity limits, and bound endpoint claims. Sources retain
calibration, model identity, joint mapping and collision/physical qualification.
Stages are half-open; landmarks index actual samples. Shared stage layouts can
batch with ordered `env_ids`, but source admission may still require B=1.

Same-grid rebuilding uses the plan's owned assembly input and current provenance
to regenerate commands, tracking, effects and monitor bounds. Supplied geometry
cannot survive a changed event pose without an explicit new input. Existing
non-joint plans and Skills without a contract retain their previous rebuild
path. Changed-grid execution, extra source recovery capabilities and phase
expansion permissions are separate contracts.
25 changes: 25 additions & 0 deletions agent_context/topics/data-pipeline/data-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ belongs to [data-assets](../data-assets/data-assets.md).
| Commit/discard/finalization dispatch | `embodichain/lab/gym/envs/managers/dataset_manager.py` |
| Synchronous LeRobot persistence | `embodichain/lab/gym/envs/managers/datasets.py`: `LeRobotRecorder` |
| Background persistence | `embodichain/lab/gym/envs/managers/async_datasets.py`: `AsyncLeRobotRecorder` |
| Real joint recordings and auditable normalization | `embodichain/data_pipeline/real2sim/`; optional external-file example in `examples/real2sim/` |
| Depth sidecars | `embodichain/data_pipeline/depth_video/writer.py`, `reader.py` |
| Offline collection retries and final partial batch | `embodichain/lab/scripts/run_env.py` |
| File-only validation and grouped quality splits | `embodichain/data_pipeline/datasets/inspection.py`; `embodichain dataset validate\|split` |
Expand All @@ -26,6 +27,20 @@ for fragment transactions, async ownership, depth output and shutdown. Read
[offline dataset tools](offline-datasets.md) for lineage, quality filtering,
validation, and conversion across Python/LeRobot versions.

## Real trajectory inputs

`real2sim/contracts.py` owns dataset-independent, immutable source/joint/phase
values. `normalization.py` maps explicit units and joint names onto a supplied
full-robot layout; missing independent joints require declared holds, and mimic
values derive from drivers. The host supplies the control clock. Pure anchored
resampling lives in `compute/trajectory/anchored.py`; reports reference array
keys/hashes while the unit retains the actual bidirectional timing maps.
Unverified inputs may be normalized diagnostically but cannot enter
`motion.expansion.Real2SimSourceAdapter`. That adapter exports narrower free
permission windows to protect derivative stencils; full semantic phase ranges
remain in the normalized unit. Raw EEF evidence has explicit measured/derived
provenance. These contracts own no scene reconstruction, reset or persistence.

## Online worker contract

Shared image buffers are allocated by `init_rollout_buffer_from_config()` in
Expand Down Expand Up @@ -127,3 +142,13 @@ Measure writer throughput using a runnable task, recording hardware, image size,
environment count and writer settings alongside the results.
The CPU-only `benchmark_segment_annotations.py` isolates the validated frame-map
lookup from simulation and storage costs.

`real2sim/bundle.py` persists raw source declarations and NPZ sidecars with
required content hashes, then reruns normalization at load. Formal admission
requires reviewed calibration and annotations. `real2sim/gripper.py` decodes an
explicit scalar/width convention through a versioned lookup; model-only estimates
remain unverified. Task Program source selection and Skill plan assembly belong
to `task_program/integrations`, not this data layer.
`gripper_release_duration` measures trailing release evidence from host-supplied
measured-open/contact masks; calibration and physical task acceptance stay with
the host, independently of source-input eligibility.
11 changes: 10 additions & 1 deletion agent_context/topics/motion-planning/motion-planning.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
| Cartesian geometry and scalar timing | `embodichain/lab/sim/motion/planners/se3.py`, `bezier.py`, `_scalar_time_law.py`, `_blend_constraints.py` in that directory |
| Collision planning and scene conversion | `embodichain/lab/sim/motion/planners/curobo/` |
| NMG policy rollout and export metadata | `embodichain/lab/sim/motion/planners/neural_planner.py` |
| Anchored source-time resampling and audit maps | `embodichain/compute/trajectory/anchored.py` |
| Real2sim qpos source adaptation | `embodichain/lab/sim/motion/expansion/real2sim.py`; raw contracts belong to [data pipeline](../data-pipeline/data-pipeline.md) |
| Pure interpolation, resampling and retiming | `embodichain/compute/trajectory/` |
| Standalone playback and B=1 expansion host lifecycle | `embodichain/lab/sim/motion/execution.py` |
| Expansion Profile loading, source adapters, candidate coordination and coverage | `embodichain/lab/sim/motion/expansion/` |
Expand Down Expand Up @@ -62,7 +64,14 @@ do not establish continuous collision freedom or derivative compliance.
## Compute and execution ownership

`compute.trajectory` owns pure interpolation, differentiation, resampling and
warping. New consumers import it directly; `lab.sim.utility.action_utils` keeps
warping. `anchored_batch.py` adds ragged tensor batches with explicit source and
anchor counts. CPU float64 mapping preparation shares the single-path algorithm;
`AnchoredBatchPlan.apply` reuses device maps through Torch or explicit Warp
CPU/CUDA kernels. Anchors stay exact, padding holds the last valid state, and
valid counts/masks exclude it from downstream evaluation. Allocation limits
cover the padded grid and output elements. The NumPy single-path API and the
B=1 registered source integration remain unchanged. New consumers import compute
directly; `lab.sim.utility.action_utils` keeps
solver-dependent pose/IK adaptation and compatibility re-exports. Trapezoidal/
Double-S Warp profiles live in `compute/kinematics/_warp/trapezoidal.py`; compute
must not import simulation objects.
Expand Down
24 changes: 24 additions & 0 deletions agent_context/topics/task-programs/task-programs.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Semantic Calls and their scene/profile/effect contracts live inside
| Compiled program model and AST expansion | `embodichain/lab/task_program/compiler/program.py` |
| Semantic Call analysis and lowering | `embodichain/lab/task_program/compiler/lowering.py` |
| Semantic Call execution | `embodichain/lab/task_program/runtime/executor.py`, `results.py` |
| Trusted nominal plan source hook | `runtime/expansion.py`: `TaskProgramNominalPlanFactory`; `integrations/environment.py`: runtime/bridge assembly |
| Grounded call plan-transform request | `embodichain/lab/task_program/runtime/expansion.py` |
| Parallel scheduling and safety boundary | `embodichain/lab/task_program/runtime/parallel.py`, `parallel_executor.py` |
| Semantic Calls, scene, profile, effects, evidence | `embodichain/lab/task_program/semantics/` |
Expand Down Expand Up @@ -80,6 +81,29 @@ Atomic plan transform; the bridge exposes immutable
`TaskProgramExpansionRecord` provenance. Nonmatching calls and episodes
without a profile keep the ordinary path.

A trusted `TaskProgramNominalPlanFactory` can provide a complete call-scoped
plan before ordinary Atomic planning. The engine snapshots and validates that
plan, then applies any existing plan transform. Execution sessions retain the
source during recovery and invocation revisions; source errors do not fall back
to another planner. `integrations/expert_sources.py` owns immutable versioned
factories, exact expanded call selections and capability preflight. The simulation
catalog fingerprints those declarations; configured task integrations select
`runtime_services.expert_source_providers` by stable IDs and content-pinned source
bundles. Bundle paths resolve from the integration file. Runtime assembly creates
fresh providers sharing the existing planning scene and embodiment profile.
Identity checks use weak references, so completed calls do not retain their
recordings; provider implementations must support weak references. Fixed-qpos
admission checks interval speeds as well as differentiated velocity references.

The first registered source is B=1 fixed-qpos Pick replay. It uses the
[source-independent Skill trajectory assembler](../atomic-actions/execution.md#trajectory-backed-plan-assembly),
with the Skill owning semantic stages and pending effects. Skill trajectory
schemas are included in registration fingerprints.
Unverified input bundles, automatic replanning/retry policies, parallel segments
and configured combined expansion fail closed. Physical qualification and
receipt-backed source attachments remain separate host work. Do not insert
executable provider syntax into program YAML.

The configured combined transform supports batches and Pick Affordance
expansion; timing expansion is not connected to this transform. Batch expansion
records retain the stable environment IDs from the planning context, including
Expand Down
12 changes: 6 additions & 6 deletions docs/architecture/curated.json
Original file line number Diff line number Diff line change
Expand Up @@ -3499,9 +3499,9 @@
{
"path": "embodichain/lab/task_program/integrations/environment.py",
"symbol": "TaskProgramEnvironmentAdapter._assemble_execution_runtime",
"start_line": 768,
"end_line": 776,
"excerpt": " runtime = SemanticCallExecutor(\n semantic.compiler,\n observation_provider,\n command_sink,\n evidence_collector,\n clock=clock,\n runner_cfg=deepcopy(selected_runner_cfg),\n plan_transform_factory=plan_transform_factory,\n )"
"start_line": 804,
"end_line": 813,
"excerpt": " runtime = SemanticCallExecutor(\n semantic.compiler,\n observation_provider,\n command_sink,\n evidence_collector,\n clock=clock,\n runner_cfg=deepcopy(selected_runner_cfg),\n plan_transform_factory=plan_transform_factory,\n nominal_plan_factory=nominal_plan_factory,\n )"
}
]
},
Expand Down Expand Up @@ -3578,9 +3578,9 @@
{
"path": "embodichain/lab/task_program/runtime/executor.py",
"symbol": "SemanticCallExecutor._prepare_grounded_call",
"start_line": 969,
"end_line": 974,
"excerpt": " session = self._engine.start(\n (invocation,),\n context,\n eligible_mask=active_mask,\n plan_transform=plan_transform,\n )"
"start_line": 1108,
"end_line": 1114,
"excerpt": " session = self._engine.start(\n (invocation,),\n context,\n eligible_mask=active_mask,\n plan_transform=plan_transform,\n nominal_plan_provider=nominal_plan_provider,\n )"
}
]
},
Expand Down
Loading
Loading