Class: Hitch::MCP::Internal::Observation
- Inherits:
-
Object
- Object
- Hitch::MCP::Internal::Observation
- Defined in:
- app/models/hitch/mcp/internal/observation.rb
Overview
Request-local structural telemetry. The state never crosses the public Context or SDK server_context boundary, and publication temporarily detaches it so hostile subscribers cannot recursively observe their own work as part of the request.
Class Method Summary collapse
- .current_request_id ⇒ Object
- .identity_keys(principal:, client_id:, key_generator: Rails.application.key_generator) ⇒ Object
- .publish(event_name, payload) ⇒ Object
- .report_failure(event_name, category) ⇒ Object
- .response_bytes(response) ⇒ Object
- .start_invocation(tool_name:) ⇒ Object
- .with_request_state ⇒ Object
Class Method Details
.current_request_id ⇒ Object
246 247 248 249 250 |
# File 'app/models/hitch/mcp/internal/observation.rb', line 246 def current_request_id correlation_id(current_request&.request_id) rescue StandardError, SystemStackError nil end |
.identity_keys(principal:, client_id:, key_generator: Rails.application.key_generator) ⇒ Object
267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'app/models/hitch/mcp/internal/observation.rb', line 267 def identity_keys(principal:, client_id:, key_generator: Rails.application.key_generator) record_class = principal.class.respond_to?(:base_class) ? principal.class.base_class : principal.class principal_type = record_class.name unless principal_type.is_a?(String) && PRINCIPAL_TYPE_PATTERN.match?(principal_type) raise ArgumentError, "MCP observation principal type is invalid" end = "MCP observation identity is invalid" principal_id = HmacIdentity.component(principal.id.to_s, invalid_message:) client = HmacIdentity.component(client_id, invalid_message:) principal_key = identity_digest([ "principal", principal_type, principal_id ], key_generator) client_key = identity_digest([ "client", client ], key_generator) [ principal_type.dup.freeze, principal_key, client_key ].freeze end |
.publish(event_name, payload) ⇒ Object
252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'app/models/hitch/mcp/internal/observation.rb', line 252 def publish(event_name, payload) previous = ActiveSupport::IsolatedExecutionState[CURRENT_REQUEST_KEY] ActiveSupport::IsolatedExecutionState.delete(CURRENT_REQUEST_KEY) ActiveSupport::Notifications.instrument(event_name, payload) rescue StandardError, SystemStackError report_failure(event_name, "subscriber") nil ensure if previous ActiveSupport::IsolatedExecutionState[CURRENT_REQUEST_KEY] = previous else ActiveSupport::IsolatedExecutionState.delete(CURRENT_REQUEST_KEY) end end |
.report_failure(event_name, category) ⇒ Object
290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'app/models/hitch/mcp/internal/observation.rb', line 290 def report_failure(event_name, category) SanitizedReport.emit( source: "hitch.mcp.observation", message: "Hitch MCP observation delivery failed", context: { hitch_mcp_category: "observation_#{category}".freeze, hitch_mcp_event: event_name.dup.freeze }.freeze ) rescue StandardError, SystemStackError nil end |
.response_bytes(response) ⇒ Object
282 283 284 285 286 287 288 |
# File 'app/models/hitch/mcp/internal/observation.rb', line 282 def response_bytes(response) body = response.body return body.bytesize if body.is_a?(String) return 0 if body.nil? Array(body).sum { |part| part.to_s.bytesize } end |
.start_invocation(tool_name:) ⇒ Object
239 240 241 242 243 244 |
# File 'app/models/hitch/mcp/internal/observation.rb', line 239 def start_invocation(tool_name:) current_request&.start_invocation(tool_name:) rescue StandardError, SystemStackError report_failure(INVOCATION_EVENT, "invocation_start") nil end |
.with_request_state ⇒ Object
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'app/models/hitch/mcp/internal/observation.rb', line 216 def with_request_state previous = ActiveSupport::IsolatedExecutionState[CURRENT_REQUEST_KEY] state = begin created = RequestState.new ActiveSupport::IsolatedExecutionState[CURRENT_REQUEST_KEY] = created created rescue StandardError, SystemStackError report_failure(REQUEST_EVENT, "request_start") nil end yield state ensure begin if previous ActiveSupport::IsolatedExecutionState[CURRENT_REQUEST_KEY] = previous else ActiveSupport::IsolatedExecutionState.delete(CURRENT_REQUEST_KEY) end rescue StandardError, SystemStackError report_failure(REQUEST_EVENT, "request_cleanup") end end |