Repository navigation
fix(evaluators): normalize records with galileo-core - #277
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Some others flagged MEDIUM by agent,
- Unreachable int branch in _GalileoJSONEncoder.default — normalization.py:54-55
if isinstance(value, int) and not isinstance(value, bool):
return value if -_MAX_SAFE_INTEGER <= value <= _MAX_SAFE_INTEGER else str(value)
json.JSONEncoder.default() is only called for types the base encoder can't handle natively. Python int is handled natively — this branch is never reached via json.dumps(). The test at test_records_factory.py:770 calls
encoder.default(2**53) directly, bypassing normal dispatch, so it passes misleadingly.
- Enum.value not recursively normalized in _GalileoJSONEncoder.default — normalization.py:45-46
if isinstance(value, Enum):
return value.value
If an enum's .value is itself non-serializable, json.dumps will fail or recurse unexpectedly. Compare with _sdk_json_value at normalization.py:73-74, which correctly recurses: return _sdk_json_value(value.value, active=active).
- _json_compatible silently passes set/bytes/Path through — normalization.py:131-141
set and frozenset are not Sequence, so they fall through to return value at line 141, unchanged. This is inconsistent with _sdk_json_value which explicitly handles set | frozenset at normalization.py:106-107. Downstream Pydantic
validation may reject the raw set.
- Dead duplicate fallback in session_output — normalization.py:454-456
if all(isinstance(item, Mapping) for item in value):
return [_json_compatible(item) for item in value]
return [_json_compatible(item) for item in value] # identical
Both branches are identical. One was presumably meant to call cls.json_text(value) for non-mapping sequences, but was never finished.
- GalileoRecordNormalizer exported in all without clear intent — records/init.py:16
"GalileoRecordNormalizer",
This is an internal normalization class with no public documentation. Exporting it makes its method signatures part of the semver contract. If it's intended for internal use only, it should be removed from all (or prefixed with _).
|
_
_ This export is intentional. GalileoRecordNormalizer is the shared normalization utility for Galileo evaluator integrations, including future LLMAJ and registered-code evaluators. It remains inside the Galileo evaluator package and does not become part of generic Agent Control. We will keep the export and maintain its canonical Galileo model behavior. |
Agreed. json.JSONEncoder.default() is not called for native Python integers, so this branch is unreachable through json.dumps(). We will remove it and keep safe-integer conversion in _sdk_json_value(). We will also update _json_text() to use that path for top-level integers and replace the direct encoder.default() test with public serializer tests. This preserves Galileo core model types while validating the actual wire-format behavior. |
Valid comment. Galileo core already serializes its standard enum fields through Pydantic. This custom normalizer also handles enums nested in metadata and other arbitrary values, so returning value.value directly can leave non-serializable values. We will recursively normalize enum values through _sdk_json_value() and add focused coverage. This does not change Galileo core model types. |
Valid comment. I will normalize sets, bytes, paths, and nested model values using the same JSON-safe behavior as _sdk_json_value(). Will add coverage for nested values and verify that the normalized output passes json.dumps() and can be reconstructed with json.loads() in Orbit. This changes only the serialized representation and does not alter Galileo core model types. |
|
Summary
splunk-aodependency withgalileo-core.BaseStepsubclasses and round-trip through their typed JSON schemas, including nested traces and sessions.RecordTypeAdapterafter adding execution IDs and parent/session/trace relationships, matching the conversion input used by Orbit'sexecute_evaluator.The Luna evaluator is intentionally unchanged and does not call this factory. The factory output is the concrete step model shape a future scorer-invocation path can hydrate and pass to
execute_evaluator. That path must still assign unique step IDs and provide the authenticated execution context; this PR does not add scorer execution or authorization.Validation
make -C evaluators/contrib/galileo check— 166 passed; lint and typecheck passed.