mujoco-react 10.2.0 → 10.3.0

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.
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
- import { withContacts, getContact, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY } from './chunk-3BMNRSS2.js';
2
- export { CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY, ModelActuators, ModelBodies, ModelCameras, ModelGeoms, ModelJoints, ModelKeyframes, ModelResources, ModelSensors, ModelSites, ScenarioLighting, SplatEnvironment, SplatEnvironmentReadinessStatus, VisualScenarioEffects, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withSplatEnvironment } from './chunk-3BMNRSS2.js';
1
+ import { withContacts, getContact, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY } from './chunk-6AZEFI6A.js';
2
+ export { CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY, ModelActuators, ModelBodies, ModelCameras, ModelGeoms, ModelJoints, ModelKeyframes, ModelResources, ModelSensors, ModelSites, ScenarioLighting, SplatEnvironment, SplatEnvironmentReadinessStatus, VisualScenarioEffects, captureCameraFrame, captureCameraFrameBlob, createCameraFrameCaptureSession, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withSplatEnvironment } from './chunk-6AZEFI6A.js';
3
3
  import loadMujoco from '@mujoco/mujoco';
4
4
  import defaultMujocoWasmUrl from '@mujoco/mujoco/mujoco.wasm?url';
5
- import { createContext, forwardRef, useEffect, useContext, useState, useRef, useCallback, useMemo, useLayoutEffect } from 'react';
5
+ import { createContext, forwardRef, useRef, useEffect, useContext, useState, useCallback, useMemo, useLayoutEffect } from 'react';
6
6
  import { jsx, jsxs } from 'react/jsx-runtime';
7
7
  import { Canvas, useThree, useFrame } from '@react-three/fiber';
8
8
  import * as THREE11 from 'three';
9
+ import { mergeVertices } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
9
10
  import { PivotControls } from '@react-three/drei';
10
11
 
11
12
  var MujocoContext = createContext({
@@ -43,6 +44,8 @@ function MujocoProvider({
43
44
  const [error, setError] = useState(null);
44
45
  const moduleRef = useRef(null);
45
46
  const isMounted = useRef(true);
47
+ const onErrorRef = useRef(onError);
48
+ onErrorRef.current = onError;
46
49
  useEffect(() => {
47
50
  isMounted.current = true;
48
51
  const variant = resolveWasmVariant(wasmVariant, threadedLoader, mtWasmUrl);
@@ -50,7 +53,7 @@ function MujocoProvider({
50
53
  const err = new Error('MujocoProvider wasmVariant="threaded" requires a threadedLoader from @mujoco/mujoco/mt');
51
54
  setError(err.message);
52
55
  setStatus("error");
53
- onError?.(err);
56
+ onErrorRef.current?.(err);
54
57
  return;
55
58
  }
56
59
  let selectedWasmUrl = wasmUrl ?? defaultMujocoWasmUrl;
@@ -59,7 +62,7 @@ function MujocoProvider({
59
62
  const err = new Error('MujocoProvider wasmVariant="threaded" requires mtWasmUrl from @mujoco/mujoco/mt/mujoco.wasm?url');
60
63
  setError(err.message);
61
64
  setStatus("error");
62
- onError?.(err);
65
+ onErrorRef.current?.(err);
63
66
  return;
64
67
  }
65
68
  selectedWasmUrl = mtWasmUrl;
@@ -90,13 +93,13 @@ function MujocoProvider({
90
93
  const msg = err.message || "Failed to init spatial simulation";
91
94
  setError(msg);
92
95
  setStatus("error");
93
- onError?.(new Error(msg));
96
+ onErrorRef.current?.(new Error(msg));
94
97
  }
95
98
  });
96
99
  return () => {
97
100
  isMounted.current = false;
98
101
  };
99
- }, [wasmUrl, mtWasmUrl, threadedLoader, wasmVariant, timeout, onError]);
102
+ }, [wasmUrl, mtWasmUrl, threadedLoader, wasmVariant, timeout]);
100
103
  return /* @__PURE__ */ jsx(
101
104
  MujocoContext.Provider,
102
105
  {
@@ -891,11 +894,20 @@ function collectDependencyPaths(xmlString, currentFile, parser) {
891
894
  }
892
895
 
893
896
  // src/rendering/GeomBuilder.ts
897
+ var DEFAULT_MESH_NORMAL_SMOOTHING_TOLERANCE = 1e-4;
894
898
  var GeomBuilder = class {
895
899
  mujoco;
896
900
  textureCache = /* @__PURE__ */ new Map();
897
- constructor(mujoco) {
901
+ renderOptions;
902
+ constructor(mujoco, renderOptions) {
898
903
  this.mujoco = mujoco;
904
+ this.renderOptions = renderOptions;
905
+ }
906
+ getMeshNormalSmoothingTolerance() {
907
+ const smoothing = this.renderOptions?.meshNormalSmoothing;
908
+ if (!smoothing) return null;
909
+ if (smoothing === true) return DEFAULT_MESH_NORMAL_SMOOTHING_TOLERANCE;
910
+ return smoothing.tolerance ?? DEFAULT_MESH_NORMAL_SMOOTHING_TOLERANCE;
899
911
  }
900
912
  getMaterialTexture(mjModel, matId) {
901
913
  if (matId < 0 || !mjModel.mat_texid || !mjModel.tex_data) return null;
@@ -990,6 +1002,10 @@ var GeomBuilder = class {
990
1002
  geo = new THREE11.BufferGeometry();
991
1003
  geo.setAttribute("position", new THREE11.Float32BufferAttribute(mjModel.mesh_vert.subarray(vAdr * 3, (vAdr + vNum) * 3), 3));
992
1004
  geo.setIndex(Array.from(mjModel.mesh_face.subarray(fAdr * 3, (fAdr + fNum) * 3)));
1005
+ const smoothingTolerance = this.getMeshNormalSmoothingTolerance();
1006
+ if (smoothingTolerance !== null) {
1007
+ geo = mergeVertices(geo, smoothingTolerance);
1008
+ }
993
1009
  geo.computeVertexNormals();
994
1010
  }
995
1011
  if (geo) {
@@ -1020,7 +1036,13 @@ var GeomBuilder = class {
1020
1036
  return null;
1021
1037
  }
1022
1038
  };
1023
- function SceneRenderer(props) {
1039
+ function getRenderOptionsKey(renderOptions) {
1040
+ const smoothing = renderOptions?.meshNormalSmoothing;
1041
+ if (!smoothing) return "default";
1042
+ if (smoothing === true) return "meshNormalSmoothing:true";
1043
+ return `meshNormalSmoothing:${smoothing.tolerance ?? "default"}`;
1044
+ }
1045
+ function SceneRenderer({ renderOptions, ...props }) {
1024
1046
  const {
1025
1047
  mjModelRef,
1026
1048
  mjDataRef,
@@ -1034,17 +1056,22 @@ function SceneRenderer(props) {
1034
1056
  const groupRef = useRef(null);
1035
1057
  const bodyRefs = useRef([]);
1036
1058
  const prevModelRef = useRef(null);
1059
+ const prevRenderOptionsKeyRef = useRef(null);
1060
+ const renderOptionsKey = getRenderOptionsKey(renderOptions);
1037
1061
  const geomBuilder = useMemo(() => {
1038
1062
  if (status !== "ready") return null;
1039
- return new GeomBuilder(mujocoRef.current);
1040
- }, [status, mujocoRef]);
1063
+ return new GeomBuilder(mujocoRef.current, renderOptions);
1064
+ }, [status, mujocoRef, renderOptionsKey]);
1041
1065
  useEffect(() => {
1042
1066
  if (status !== "ready" || !geomBuilder) return;
1043
1067
  const model = mjModelRef.current;
1044
1068
  const group = groupRef.current;
1045
1069
  if (!model || !group) return;
1046
- if (prevModelRef.current === model) return;
1070
+ if (prevModelRef.current === model && prevRenderOptionsKeyRef.current === renderOptionsKey) {
1071
+ return;
1072
+ }
1047
1073
  prevModelRef.current = model;
1074
+ prevRenderOptionsKeyRef.current = renderOptionsKey;
1048
1075
  while (group.children.length > 0) {
1049
1076
  group.remove(group.children[0]);
1050
1077
  }
@@ -1065,7 +1092,7 @@ function SceneRenderer(props) {
1065
1092
  refs.push(bodyGroup);
1066
1093
  }
1067
1094
  bodyRefs.current = refs;
1068
- }, [status, geomBuilder, mjModelRef]);
1095
+ }, [status, geomBuilder, mjModelRef, renderOptionsKey]);
1069
1096
  const syncBodiesToData = useCallback(() => {
1070
1097
  const data = mjDataRef.current;
1071
1098
  if (!data) return;
@@ -1930,6 +1957,106 @@ function applyMountedCameraPoseOffsets(options, position, quaternion) {
1930
1957
  ]
1931
1958
  };
1932
1959
  }
1960
+ function resolveMujocoCameraCompatibilityOptions(options) {
1961
+ const compatibility = options.mujocoCameraCompatibility;
1962
+ if (!compatibility) return null;
1963
+ if (compatibility === true) {
1964
+ return {
1965
+ useResolution: true,
1966
+ useIntrinsics: true,
1967
+ useClipping: true,
1968
+ preserveAspect: true,
1969
+ preferResolution: false
1970
+ };
1971
+ }
1972
+ return {
1973
+ useResolution: compatibility.useResolution ?? true,
1974
+ useIntrinsics: compatibility.useIntrinsics ?? true,
1975
+ useClipping: compatibility.useClipping ?? true,
1976
+ preserveAspect: compatibility.preserveAspect ?? true,
1977
+ preferResolution: compatibility.preferResolution ?? false
1978
+ };
1979
+ }
1980
+ function mujocoVisualClip(model) {
1981
+ const map = model.vis?.map;
1982
+ const near = typeof map?.znear === "number" && map.znear > 0 ? map.znear : void 0;
1983
+ const far = typeof map?.zfar === "number" && map.zfar > 0 ? map.zfar : void 0;
1984
+ return { near, far };
1985
+ }
1986
+ function mujocoCameraResolution(model, cameraId) {
1987
+ const resolution = model.cam_resolution;
1988
+ if (!resolution) return {};
1989
+ const width = Number(resolution[cameraId * 2]);
1990
+ const height = Number(resolution[cameraId * 2 + 1]);
1991
+ return {
1992
+ width: Number.isFinite(width) && width > 0 ? width : void 0,
1993
+ height: Number.isFinite(height) && height > 0 ? height : void 0
1994
+ };
1995
+ }
1996
+ function mujocoCameraProjectionMatrix(model, cameraId, width, height, near, far) {
1997
+ const intrinsic = model.cam_intrinsic;
1998
+ const sensorSize = model.cam_sensorsize;
1999
+ if (!intrinsic || !sensorSize || !width || !height) return void 0;
2000
+ const intrinsicOffset = cameraId * 4;
2001
+ const sensorOffset = cameraId * 2;
2002
+ const focalX = Number(intrinsic[intrinsicOffset]);
2003
+ const focalY = Number(intrinsic[intrinsicOffset + 1]);
2004
+ const principalX = Number(intrinsic[intrinsicOffset + 2]);
2005
+ const principalY = Number(intrinsic[intrinsicOffset + 3]);
2006
+ const sensorWidth = Number(sensorSize[sensorOffset]);
2007
+ const sensorHeight = Number(sensorSize[sensorOffset + 1]);
2008
+ if (!Number.isFinite(focalX) || !Number.isFinite(focalY) || !Number.isFinite(principalX) || !Number.isFinite(principalY) || !Number.isFinite(sensorWidth) || !Number.isFinite(sensorHeight) || focalX <= 0 || focalY <= 0 || sensorWidth <= 0 || sensorHeight <= 0) {
2009
+ return void 0;
2010
+ }
2011
+ const fx = focalX / sensorWidth * width;
2012
+ const fy = focalY / sensorHeight * height;
2013
+ const cx = width * (0.5 + principalX / sensorWidth);
2014
+ const cy = height * (0.5 + principalY / sensorHeight);
2015
+ const znear = near ?? 0.01;
2016
+ const zfar = far ?? 100;
2017
+ return new THREE11.Matrix4().set(
2018
+ 2 * fx / width,
2019
+ 0,
2020
+ 1 - 2 * cx / width,
2021
+ 0,
2022
+ 0,
2023
+ 2 * fy / height,
2024
+ 2 * cy / height - 1,
2025
+ 0,
2026
+ 0,
2027
+ 0,
2028
+ -(zfar + znear) / (zfar - znear),
2029
+ -2 * zfar * znear / (zfar - znear),
2030
+ 0,
2031
+ 0,
2032
+ -1,
2033
+ 0
2034
+ );
2035
+ }
2036
+ function resolveMujocoCameraCaptureDimensions(requested, cameraResolution, compatibility) {
2037
+ if (!compatibility.useResolution) {
2038
+ return {
2039
+ width: requested.width,
2040
+ height: requested.height
2041
+ };
2042
+ }
2043
+ if (compatibility.preferResolution) {
2044
+ return {
2045
+ width: cameraResolution.width ?? requested.width,
2046
+ height: cameraResolution.height ?? requested.height
2047
+ };
2048
+ }
2049
+ let width = requested.width ?? cameraResolution.width;
2050
+ let height = requested.height ?? cameraResolution.height;
2051
+ if (compatibility.preserveAspect && cameraResolution.width && cameraResolution.height) {
2052
+ if (requested.width !== void 0 && requested.height === void 0) {
2053
+ height = requested.width * cameraResolution.height / cameraResolution.width;
2054
+ } else if (requested.height !== void 0 && requested.width === void 0) {
2055
+ width = requested.height * cameraResolution.width / cameraResolution.height;
2056
+ }
2057
+ }
2058
+ return { width, height };
2059
+ }
1933
2060
  function countMountedCameraSelectors(options) {
1934
2061
  return Number(Boolean(options.cameraName)) + Number(Boolean(options.siteName)) + Number(Boolean(options.bodyName));
1935
2062
  }
@@ -2033,6 +2160,7 @@ function MujocoSimProvider({
2033
2160
  paused,
2034
2161
  speed,
2035
2162
  interpolate,
2163
+ renderOptions,
2036
2164
  children
2037
2165
  }) {
2038
2166
  const { gl, camera, scene } = useThree();
@@ -2067,24 +2195,12 @@ function MujocoSimProvider({
2067
2195
  const bodyRegistryRef = useRef(/* @__PURE__ */ new Map());
2068
2196
  const hiddenBodiesRef = useRef(/* @__PURE__ */ new Set());
2069
2197
  const bodyReloadTimerRef = useRef(null);
2070
- useEffect(() => {
2071
- configRef.current = config;
2072
- }, [config]);
2073
- useEffect(() => {
2074
- mujocoRef.current = mujoco;
2075
- }, [mujoco]);
2076
- useEffect(() => {
2077
- pausedRef.current = paused ?? false;
2078
- }, [paused]);
2079
- useEffect(() => {
2080
- speedRef.current = speed ?? 1;
2081
- }, [speed]);
2082
- useEffect(() => {
2083
- substepsRef.current = substeps ?? 1;
2084
- }, [substeps]);
2085
- useEffect(() => {
2086
- interpolateRef.current = interpolate ?? false;
2087
- }, [interpolate]);
2198
+ configRef.current = config;
2199
+ mujocoRef.current = mujoco;
2200
+ pausedRef.current = paused ?? false;
2201
+ speedRef.current = speed ?? 1;
2202
+ substepsRef.current = substeps ?? 1;
2203
+ interpolateRef.current = interpolate ?? false;
2088
2204
  useEffect(() => {
2089
2205
  if (!gravity) return;
2090
2206
  const model = mjModelRef.current;
@@ -2590,11 +2706,27 @@ function MujocoSimProvider({
2590
2706
  for (let i = 0; i < ncam; i += 1) {
2591
2707
  const posOffset = i * 3;
2592
2708
  const quatOffset = i * 4;
2709
+ const intrinsicOffset = i * 4;
2710
+ const resolutionOffset = i * 2;
2593
2711
  result.push({
2594
2712
  id: i,
2595
2713
  name: getName(model, nameAddresses[i]),
2596
2714
  bodyId: model.cam_bodyid?.[i] ?? -1,
2597
2715
  fov: model.cam_fovy?.[i] ?? null,
2716
+ resolution: model.cam_resolution ? [
2717
+ model.cam_resolution[resolutionOffset],
2718
+ model.cam_resolution[resolutionOffset + 1]
2719
+ ] : null,
2720
+ sensorSize: model.cam_sensorsize ? [
2721
+ model.cam_sensorsize[resolutionOffset],
2722
+ model.cam_sensorsize[resolutionOffset + 1]
2723
+ ] : null,
2724
+ intrinsic: model.cam_intrinsic ? [
2725
+ model.cam_intrinsic[intrinsicOffset],
2726
+ model.cam_intrinsic[intrinsicOffset + 1],
2727
+ model.cam_intrinsic[intrinsicOffset + 2],
2728
+ model.cam_intrinsic[intrinsicOffset + 3]
2729
+ ] : null,
2598
2730
  position: model.cam_pos ? vector3FromArray(model.cam_pos, posOffset) : null,
2599
2731
  quaternion: model.cam_quat ? quaternionFromMujocoQuat(model.cam_quat, quatOffset) : null
2600
2732
  });
@@ -2622,10 +2754,22 @@ function MujocoSimProvider({
2622
2754
  );
2623
2755
  }
2624
2756
  const pose = applyMountedCameraPoseOffsets(options, position, quaternion);
2757
+ const compatibility = resolveMujocoCameraCompatibilityOptions(options);
2758
+ const cameraResolution = compatibility?.useResolution ? mujocoCameraResolution(model, cameraId) : { width: void 0, height: void 0 };
2759
+ const clip = compatibility?.useClipping ? mujocoVisualClip(model) : { near: void 0, far: void 0 };
2760
+ const { width, height } = compatibility ? resolveMujocoCameraCaptureDimensions(options, cameraResolution, compatibility) : { width: options.width, height: options.height };
2761
+ const near = options.near ?? clip.near;
2762
+ const far = options.far ?? clip.far;
2763
+ const projectionMatrix = compatibility?.useIntrinsics ? mujocoCameraProjectionMatrix(model, cameraId, width, height, near, far) : void 0;
2625
2764
  return {
2626
2765
  ...baseOptions,
2766
+ width,
2767
+ height,
2627
2768
  ...pose,
2628
2769
  fov: options.fov ?? model.cam_fovy?.[cameraId],
2770
+ near,
2771
+ far,
2772
+ projectionMatrix: options.projectionMatrix ?? projectionMatrix,
2629
2773
  source: { kind: "mujoco-camera", cameraName: options.cameraName }
2630
2774
  };
2631
2775
  }
@@ -3271,7 +3415,7 @@ function MujocoSimProvider({
3271
3415
  [api, status, requestBodyReload]
3272
3416
  );
3273
3417
  return /* @__PURE__ */ jsxs(MujocoSimContext.Provider, { value: contextValue, children: [
3274
- /* @__PURE__ */ jsx(SceneRenderer, {}),
3418
+ /* @__PURE__ */ jsx(SceneRenderer, { renderOptions }),
3275
3419
  children
3276
3420
  ] });
3277
3421
  }
@@ -3289,16 +3433,19 @@ var MujocoCanvas = forwardRef(
3289
3433
  paused,
3290
3434
  speed,
3291
3435
  interpolate,
3436
+ renderOptions,
3292
3437
  loadingFallback,
3293
3438
  children,
3294
3439
  ...canvasProps
3295
3440
  }, ref) {
3296
3441
  const { mujoco, status: wasmStatus, error: wasmError } = useMujocoWasm();
3442
+ const onErrorRef = useRef(onError);
3443
+ onErrorRef.current = onError;
3297
3444
  useEffect(() => {
3298
- if (wasmStatus === "error" && onError) {
3299
- onError(new Error(wasmError ?? "WASM load failed"));
3445
+ if (wasmStatus === "error") {
3446
+ onErrorRef.current?.(new Error(wasmError ?? "WASM load failed"));
3300
3447
  }
3301
- }, [wasmStatus, wasmError, onError]);
3448
+ }, [wasmStatus, wasmError]);
3302
3449
  if (wasmStatus === "loading" || !mujoco) {
3303
3450
  return loadingFallback ? /* @__PURE__ */ jsx(Canvas, { ...canvasProps, children: loadingFallback }) : null;
3304
3451
  }
@@ -3321,6 +3468,7 @@ var MujocoCanvas = forwardRef(
3321
3468
  paused,
3322
3469
  speed,
3323
3470
  interpolate,
3471
+ renderOptions,
3324
3472
  children
3325
3473
  }
3326
3474
  ) });
@@ -3329,11 +3477,13 @@ var MujocoCanvas = forwardRef(
3329
3477
  var MujocoPhysics = forwardRef(
3330
3478
  function MujocoPhysics2({ onError, children, ...props }, ref) {
3331
3479
  const { mujoco, status: wasmStatus, error: wasmError } = useMujocoWasm();
3480
+ const onErrorRef = useRef(onError);
3481
+ onErrorRef.current = onError;
3332
3482
  useEffect(() => {
3333
- if (wasmStatus === "error" && onError) {
3334
- onError(new Error(wasmError ?? "WASM load failed"));
3483
+ if (wasmStatus === "error") {
3484
+ onErrorRef.current?.(new Error(wasmError ?? "WASM load failed"));
3335
3485
  }
3336
- }, [wasmStatus, wasmError, onError]);
3486
+ }, [wasmStatus, wasmError]);
3337
3487
  if (wasmStatus === "error" || wasmStatus === "loading" || !mujoco) {
3338
3488
  return null;
3339
3489
  }
@@ -6561,7 +6711,8 @@ function usePolicy(config) {
6561
6711
  const shouldInfer = !inFlightRef.current && (!queuedAction || actionQueueRef.current.length <= prefetchThreshold);
6562
6712
  if (!shouldInfer) return;
6563
6713
  const observation = cfg.onObservation({ model, data });
6564
- const result = cfg.infer ? cfg.infer({ observation, model, data }) : observation;
6714
+ const queuedActions = actionQueueRef.current.length;
6715
+ const result = cfg.infer ? cfg.infer({ observation, model, data, queuedActions }) : observation;
6565
6716
  if (isPromiseLike(result)) {
6566
6717
  const epoch = epochRef.current;
6567
6718
  inFlightRef.current = true;
@@ -6592,11 +6743,11 @@ function usePolicy(config) {
6592
6743
  cfg.queueStrategy ?? "append"
6593
6744
  );
6594
6745
  } else {
6595
- const [action, ...queuedActions] = actions;
6746
+ const [action, ...queuedActions2] = actions;
6596
6747
  if (!action) return;
6597
6748
  enqueuePolicyActions(
6598
6749
  actionQueueRef.current,
6599
- queuedActions,
6750
+ queuedActions2,
6600
6751
  observation,
6601
6752
  cfg.queueStrategy ?? "append"
6602
6753
  );
@@ -6739,7 +6890,7 @@ function useRemotePolicy(config) {
6739
6890
  const remoteEpochRef = useRef(0);
6740
6891
  const policy = usePolicy({
6741
6892
  ...config,
6742
- infer: async ({ observation, model, data }) => {
6893
+ infer: async ({ observation, model, data, queuedActions }) => {
6743
6894
  const cfg = configRef.current;
6744
6895
  abortController(abortControllerRef.current, createAbortError("Remote policy request was superseded."));
6745
6896
  const controller = new AbortController();
@@ -6751,6 +6902,7 @@ function useRemotePolicy(config) {
6751
6902
  observation,
6752
6903
  model,
6753
6904
  data,
6905
+ queuedActions,
6754
6906
  reset: requestIndex === 0,
6755
6907
  requestIndex,
6756
6908
  signal