reactor-runtime 2.7.7__tar.gz → 2.7.9__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 (140) hide show
  1. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/PKG-INFO +1 -1
  2. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/pyproject.toml +2 -2
  3. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/config.py +36 -1
  4. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/defaults.py +12 -0
  5. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/model_state.py +30 -3
  6. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/runtime_api.py +383 -1
  7. reactor_runtime-2.7.9/src/reactor_runtime/schema_validator.py +231 -0
  8. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/utils/messages.py +4 -0
  9. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime.egg-info/PKG-INFO +1 -1
  10. reactor_runtime-2.7.7/src/reactor_runtime/schema_validator.py +0 -123
  11. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/README.md +0 -0
  12. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/setup.cfg +0 -0
  13. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/api/__init__.py +0 -0
  14. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/__init__.py +0 -0
  15. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/experiment/__init__.py +0 -0
  16. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/experiment/session.py +0 -0
  17. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/__init__.py +0 -0
  18. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/driver/__init__.py +0 -0
  19. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/driver/pipeline_executor.py +0 -0
  20. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/driver/step_result.py +0 -0
  21. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/events/__init__.py +0 -0
  22. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/events/connected.py +0 -0
  23. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/events/event.py +0 -0
  24. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/events/messages.py +0 -0
  25. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/events/upload.py +0 -0
  26. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/internal/__init__.py +0 -0
  27. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/internal/input_buffer.py +0 -0
  28. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/internal/output_buffer.py +0 -0
  29. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/internal/reactor_core.py +0 -0
  30. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/model/__init__.py +0 -0
  31. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/model/decorators.py +0 -0
  32. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/model/handlers.py +0 -0
  33. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/model/reactor_model.py +0 -0
  34. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/pipeline/__init__.py +0 -0
  35. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/pipeline/idle.py +0 -0
  36. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/pipeline/input_state.py +0 -0
  37. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/pipeline/reactor_pipeline.py +0 -0
  38. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/tracks/__init__.py +0 -0
  39. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/tracks/descriptors.py +0 -0
  40. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/tracks/input.py +0 -0
  41. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/tracks/output.py +0 -0
  42. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/interface/upload.py +0 -0
  43. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/__init__.py +0 -0
  44. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/backends/__init__.py +0 -0
  45. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/backends/base.py +0 -0
  46. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/backends/file.py +0 -0
  47. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/backends/otlp.py +0 -0
  48. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/helpers.py +0 -0
  49. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/nvml_sampler.py +0 -0
  50. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/plotting/__init__.py +0 -0
  51. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/plotting/plot_profiling.py +0 -0
  52. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/profiler.py +0 -0
  53. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/singleton.py +0 -0
  54. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/profiling/torch_chunk_profiler.py +0 -0
  55. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/__init__.py +0 -0
  56. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/chunk_encoder.py +0 -0
  57. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/chunk_uploader.py +0 -0
  58. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/config.py +0 -0
  59. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/markers.py +0 -0
  60. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/session_recorder.py +0 -0
  61. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/sinks.py +0 -0
  62. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/recording/track_resolver.py +0 -0
  63. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/runtimes/headless/config.py +0 -0
  64. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/runtimes/headless/headless_runtime.py +0 -0
  65. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/runtimes/headless/input_feeder.py +0 -0
  66. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/runtimes/http/config.py +0 -0
  67. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/runtimes/http/http_runtime.py +0 -0
  68. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/runtimes/http/types.py +0 -0
  69. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/schema.py +0 -0
  70. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/__init__.py +0 -0
  71. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/__main__.py +0 -0
  72. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/commands/__init__.py +0 -0
  73. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/commands/run.py +0 -0
  74. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/commands/schema.py +0 -0
  75. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/main.py +0 -0
  76. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/utils/__init__.py +0 -0
  77. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/utils/config.py +0 -0
  78. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/serve/utils/runtime.py +0 -0
  79. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/__init__.py +0 -0
  80. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/aiortc/__init__.py +0 -0
  81. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/aiortc/audio_track.py +0 -0
  82. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/aiortc/client.py +0 -0
  83. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/aiortc/frame_conversion.py +0 -0
  84. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/aiortc/ice_connection.py +0 -0
  85. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/aiortc/video_track.py +0 -0
  86. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/config.py +0 -0
  87. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/events.py +0 -0
  88. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/__init__.py +0 -0
  89. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/client.py +0 -0
  90. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/__init__.py +0 -0
  91. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/av1.py +0 -0
  92. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/base.py +0 -0
  93. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/factory.py +0 -0
  94. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/h264.py +0 -0
  95. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/h265.py +0 -0
  96. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/opus.py +0 -0
  97. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/vp8.py +0 -0
  98. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/decoders/vp9.py +0 -0
  99. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/__init__.py +0 -0
  100. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/av1.py +0 -0
  101. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/base.py +0 -0
  102. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/factory.py +0 -0
  103. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/h264.py +0 -0
  104. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/h265.py +0 -0
  105. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/opus.py +0 -0
  106. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/vp8.py +0 -0
  107. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/encoders/vp9.py +0 -0
  108. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/gst.py +0 -0
  109. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/gst_helpers.py +0 -0
  110. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/probes/__init__.py +0 -0
  111. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/probes/fps_probe.py +0 -0
  112. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/receiver/__init__.py +0 -0
  113. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/receiver/audio.py +0 -0
  114. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/receiver/base.py +0 -0
  115. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/receiver/video.py +0 -0
  116. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sdp/__init__.py +0 -0
  117. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sdp/bundle.py +0 -0
  118. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sdp/codec.py +0 -0
  119. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sdp/extmap.py +0 -0
  120. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sdp/ice.py +0 -0
  121. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sender/__init__.py +0 -0
  122. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sender/audio.py +0 -0
  123. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sender/base.py +0 -0
  124. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/sender/video.py +0 -0
  125. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/settings.py +0 -0
  126. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/gstreamer/signals.py +0 -0
  127. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/ice_uris.py +0 -0
  128. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/interface.py +0 -0
  129. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/media.py +0 -0
  130. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/transports/types.py +0 -0
  131. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/utils/launch.py +0 -0
  132. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/utils/loader.py +0 -0
  133. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/utils/log.py +0 -0
  134. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/utils/paths.py +0 -0
  135. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/utils/ports.py +0 -0
  136. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime/utils/typing.py +0 -0
  137. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime.egg-info/SOURCES.txt +0 -0
  138. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime.egg-info/dependency_links.txt +0 -0
  139. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime.egg-info/requires.txt +0 -0
  140. {reactor_runtime-2.7.7 → reactor_runtime-2.7.9}/src/reactor_runtime.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reactor_runtime
3
- Version: 2.7.7
3
+ Version: 2.7.9
4
4
  Summary: Reactor runtime with public model API
5
5
  Author-email: Reactor <team@reactor.inc>
6
6
  Requires-Python: >=3.9
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "reactor_runtime"
7
- version = "2.7.7"
7
+ version = "2.7.9"
8
8
  description = "Reactor runtime with public model API"
9
9
  authors = [
10
10
  { name = "Reactor", email = "team@reactor.inc" }
@@ -87,4 +87,4 @@ gst = [
87
87
  # Legacy releases used `X.Y.Z-g<short-sha>` (e.g. `1.4.1-g5660eed`); the wheel
88
88
  # stripped the `-g<sha>` suffix. fetch-proto.py still understands that shape
89
89
  # for back-compat with old pins, but new bumps should track the calendar format.
90
- version = "1.20260514.12095"
90
+ version = "1.20260527.14467"
@@ -81,6 +81,37 @@ def _reset_legacy_warning_for_tests() -> None:
81
81
  _legacy_warned = False
82
82
 
83
83
 
84
+ @dataclass
85
+ class ModerationYamlConfig:
86
+ """Top-level ``moderation:`` block parsed from ``reactor.yaml``.
87
+
88
+ Model authors declare here whether content moderation runs for their
89
+ model. Defaults to ``enabled: false`` so existing models opt in
90
+ explicitly. Operational tuning (thresholds, concurrency, backend
91
+ choice, ``OPENAI_API_KEY``) stays in environment variables — this
92
+ block carries only the policy decision the model author owns.
93
+ """
94
+
95
+ enabled: bool = False
96
+
97
+ @classmethod
98
+ def from_dict(cls, raw: Optional[Dict[str, Any]]) -> "ModerationYamlConfig":
99
+ if not isinstance(raw, dict):
100
+ return cls()
101
+ enabled = raw.get("enabled", False)
102
+ # Strict bool check: `bool("false") is True` would silently flip
103
+ # moderation on for a YAML author who wrote `enabled: "false"`
104
+ # (quoted) or templated a `"0"` value. Safety-sensitive config —
105
+ # fail at parse time with a message that names the offending value.
106
+ if not isinstance(enabled, bool):
107
+ raise TypeError(
108
+ f"moderation.enabled in reactor.yaml must be a boolean, "
109
+ f"got {type(enabled).__name__}: {enabled!r}. "
110
+ 'Did you accidentally quote the value (e.g. "false")?'
111
+ )
112
+ return cls(enabled=enabled)
113
+
114
+
84
115
  @dataclass
85
116
  class ReactorConfig:
86
117
  """Parsed ``reactor.yaml``.
@@ -119,6 +150,7 @@ class ReactorConfig:
119
150
  config_overrides: List[str] = field(default_factory=list)
120
151
  weights_path: Optional[str] = None
121
152
  recording: RecordingConfig = field(default_factory=RecordingConfig)
153
+ moderation: ModerationYamlConfig = field(default_factory=ModerationYamlConfig)
122
154
 
123
155
  @classmethod
124
156
  def from_dict(cls, raw: Dict[str, Any]) -> "ReactorConfig":
@@ -135,8 +167,9 @@ class ReactorConfig:
135
167
  runtime_section = raw.get("runtime")
136
168
  model_section = raw.get("model")
137
169
 
138
- # Recording is a top-level sibling to runtime: / model:.
170
+ # Recording and moderation are top-level siblings to runtime: / model:.
139
171
  recording = RecordingConfig.from_dict(raw.get("recording"))
172
+ moderation = ModerationYamlConfig.from_dict(raw.get("moderation"))
140
173
 
141
174
  modern = isinstance(runtime_section, dict) or isinstance(model_section, dict)
142
175
 
@@ -161,6 +194,7 @@ class ReactorConfig:
161
194
  config=runtime_section.get("config"),
162
195
  weights_path=runtime_section.get("weights_path") or None,
163
196
  recording=recording,
197
+ moderation=moderation,
164
198
  )
165
199
 
166
200
  if "model" not in raw:
@@ -177,4 +211,5 @@ class ReactorConfig:
177
211
  config=raw.get("config"),
178
212
  weights_path=raw.get("weights_path") or None,
179
213
  recording=recording,
214
+ moderation=moderation,
180
215
  )
@@ -51,6 +51,7 @@ class FieldInfo:
51
51
  min_length: Optional[int] = None
52
52
  max_length: Optional[int] = None
53
53
  choices: Optional[List[Any]] = None
54
+ moderate: bool = True
54
55
 
55
56
 
56
57
  def InputField(
@@ -63,6 +64,7 @@ def InputField(
63
64
  min_length: Optional[int] = None,
64
65
  max_length: Optional[int] = None,
65
66
  choices: Optional[List[Any]] = None,
67
+ moderate: bool = True,
66
68
  ) -> Any:
67
69
  """Declare a default value and validation constraints for a field.
68
70
 
@@ -81,6 +83,13 @@ def InputField(
81
83
  min_length: Minimum length for string/sequence values.
82
84
  max_length: Maximum length for string/sequence values.
83
85
  choices: Exhaustive list of allowed values.
86
+ moderate: Whether to submit this field's value to the content
87
+ moderation backend (when moderation is enabled platform-wide).
88
+ Defaults to ``True``. Only effective for free-text ``str``
89
+ fields (those without ``choices=``) and ``UploadedFile``
90
+ fields — typed, enum, and numeric fields are never moderated
91
+ because the schema validator rejects out-of-set payloads
92
+ before they reach the model.
84
93
  """
85
94
  if default_factory is not None:
86
95
  raise TypeError(
@@ -95,6 +104,7 @@ def InputField(
95
104
  min_length=min_length,
96
105
  max_length=max_length,
97
106
  choices=choices,
107
+ moderate=moderate,
98
108
  )
99
109
 
100
110
 
@@ -227,3 +237,5 @@ def field_info_to_json_schema(schema: Dict[str, Any], info: FieldInfo) -> None:
227
237
  schema["maxLength"] = info.max_length
228
238
  if info.choices is not None:
229
239
  schema["enum"] = info.choices
240
+ if not info.moderate:
241
+ schema["x-reactor-moderate"] = False
@@ -31,6 +31,7 @@ class ModelEvent(Enum):
31
31
  CLEANUP_COMPLETE = "cleanup_complete"
32
32
  EVICTION = "eviction"
33
33
  IDLING = "idling"
34
+ SESSION_ACTIVE = "session_active"
34
35
 
35
36
 
36
37
  class ModelStateMachine:
@@ -72,6 +73,15 @@ class ModelStateMachine:
72
73
  ModelEvent.IDLING: [
73
74
  (ModelState.READY, ModelState.READY),
74
75
  ],
76
+ # SESSION_ACTIVE is the analog of IDLING during a live session: a
77
+ # periodic liveness ping sent while the runtime is serving a
78
+ # session (WAITING / STREAMING / ORPHANED). All three transitions
79
+ # are self-loops since the event carries no state change.
80
+ ModelEvent.SESSION_ACTIVE: [
81
+ (ModelState.WAITING, ModelState.WAITING),
82
+ (ModelState.STREAMING, ModelState.STREAMING),
83
+ (ModelState.ORPHANED, ModelState.ORPHANED),
84
+ ],
75
85
  }
76
86
 
77
87
  def __init__(self, initial_state: ModelState = ModelState.CREATED):
@@ -98,7 +108,10 @@ class ModelStateMachine:
98
108
 
99
109
  if to_state is None:
100
110
  log_fn = logger.warning
101
- if event == ModelEvent.IDLING:
111
+ # IDLING and SESSION_ACTIVE are high-frequency liveness pings;
112
+ # legitimate races with state transitions can produce rejected
113
+ # events that don't deserve a warning.
114
+ if event in (ModelEvent.IDLING, ModelEvent.SESSION_ACTIVE):
102
115
  log_fn = logger.debug
103
116
  log_fn(
104
117
  "Illegal state transition",
@@ -108,7 +121,7 @@ class ModelStateMachine:
108
121
  return False
109
122
 
110
123
  log_fn = logger.info
111
- if event == ModelEvent.IDLING:
124
+ if event in (ModelEvent.IDLING, ModelEvent.SESSION_ACTIVE):
112
125
  log_fn = logger.debug
113
126
 
114
127
  log_fn(
@@ -145,7 +158,18 @@ class ModelStateMachine:
145
158
  handler(**kwargs)
146
159
 
147
160
  def _call_enter_handler(self, state: ModelState, previous_state: ModelState):
148
- """Call the appropriate on_enter_<state> method."""
161
+ """Call the appropriate on_enter_<state> method.
162
+
163
+ Self-loop transitions (``state == previous_state``) skip the
164
+ ``on_enter_*`` hook — those hooks are designed to run on actual
165
+ state changes, not on every heartbeat. This matters for
166
+ liveness-ping events like ``IDLING`` and ``SESSION_ACTIVE`` whose
167
+ from/to states are identical: re-running ``on_enter_WAITING`` /
168
+ ``on_enter_ORPHANED`` on every tick would, e.g., cancel and
169
+ restart the orphan timeout, preventing it from ever firing.
170
+ """
171
+ if state == previous_state:
172
+ return
149
173
  handler_name = f"on_enter_{state.value}"
150
174
  handler = getattr(self, handler_name, None)
151
175
  if handler:
@@ -191,6 +215,9 @@ class ModelStateMachine:
191
215
  def on_before_idling(self, **kwargs):
192
216
  pass
193
217
 
218
+ def on_before_session_active(self, **kwargs):
219
+ pass
220
+
194
221
  # on_enter_<state> methods
195
222
  def on_enter_CREATED(self, previous_state: ModelState):
196
223
  pass