Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c17994f
feat(galileo): dual-write canonical Luna records
namrataghadi-galileo Sep 24, 2026
2cd9380
refactor(galileo): normalize records with galileo-core
namrataghadi-galileo Sep 24, 2026
50ab93f
test(galileo): remove SDK parity imports
namrataghadi-galileo Sep 24, 2026
4ce13fb
support tools in control decorator
namrataghadi-galileo Sep 27, 2026
79aafd8
fix evaluator
namrataghadi-galileo Sep 28, 2026
bc6b2d9
fix(server): annotate binding query rows
namrataghadi-galileo Sep 28, 2026
ebd2df7
test(galileo): cover record normalization paths
namrataghadi-galileo Sep 28, 2026
93f36ad
Merge branch 'main' into feature/SAO-17516-request-payload-contract
namrataghadi-galileo Sep 29, 2026
a2909f6
fix(galileo): address Luna request review feedback
namrataghadi-galileo Sep 29, 2026
0a0b03c
rebase with main
namrataghadi-galileo Oct 2, 2026
1af93a4
Merge remote-tracking branch 'origin/feature/SAO-17516-request-payloa…
namrataghadi-galileo Oct 2, 2026
a874446
add Step.children
namrataghadi-galileo Oct 5, 2026
e255845
Merge branch 'feature/SAO-18049-add-children-to-step' into feature/SA…
namrataghadi-galileo Oct 5, 2026
0fe6d6f
update requiest payload contract to use steps.children
namrataghadi-galileo Oct 6, 2026
7d2f4a5
fix(sdk-ts): update generated Step children model
namrataghadi-galileo Oct 6, 2026
c14bcc1
Merge branch 'feature/SAO-18049-add-children-to-step' into feature/SA…
namrataghadi-galileo Oct 6, 2026
38e3d95
test(galileo): align record contract assertions
namrataghadi-galileo Oct 6, 2026
9aedf2f
Merge branch 'main' into feature/SAO-17516-request-payload-contract
namrataghadi-galileo Oct 6, 2026
4d32733
fix(galileo): preserve structured Luna selector data
namrataghadi-galileo Oct 7, 2026
66c3697
fix(galileo): allow empty trace and session children
namrataghadi-galileo Oct 7, 2026
215fdd7
fix the records creation for traces and sessions
namrataghadi-galileo Oct 7, 2026
77a4763
add messages as part of input for llm records
namrataghadi-galileo Oct 7, 2026
094b0a6
address comment
namrataghadi-galileo Oct 7, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
)
from agent_control_evaluator_galileo.records import (
GalileoRecord,
GalileoRecordNormalizer,
RecordFactoryError,
UnsupportedStepTypeError,
build_galileo_record,
build_record,
record_from_scorer_invoke_record,
record_from_step,
)

Expand All @@ -51,10 +51,10 @@
"LunaOperator",
"LUNA_AVAILABLE",
"GalileoRecord",
"GalileoRecordNormalizer",
"RecordFactoryError",
"UnsupportedStepTypeError",
"build_galileo_record",
"build_record",
"record_from_scorer_invoke_record",
"record_from_step",
]
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
from hmac import new as hmac_new
from json import dumps
from time import time
from typing import Literal, cast, get_args
from typing import Any, Literal, get_args
from urllib.parse import urlsplit

import httpx
from agent_control_models import JSONObject, JSONValue, Step
from pydantic import BaseModel, Field, PrivateAttr, model_validator
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator

from ..records import UnsupportedStepTypeError, record_from_step
from .config import ScorerInvokeConfig

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -57,6 +58,7 @@
"session",
]
SUPPORTED_SCORER_INVOKE_RECORD_TYPES = frozenset(get_args(ScorerInvokeRecordType))
_MISSING_SELECTED_DATA = object()


def _b64url(data: bytes) -> str:
Expand Down Expand Up @@ -219,6 +221,8 @@ class ScorerInvokeRecord(BaseModel):
represented here. Orbit hydrates those fields from trusted server context.
"""

model_config = ConfigDict(extra="allow")

type: ScorerInvokeRecordType
name: str | None = None
input: JSONValue = None
Expand Down Expand Up @@ -272,11 +276,13 @@ def to_dict(self) -> JSONObject:
return request


def _orbit_record_from_step(
def _scorer_invoke_record_from_step(
step: Step | None,
*,
selected_input: JSONValue,
selected_output: JSONValue,
selected_data: Any = _MISSING_SELECTED_DATA,
payload_field: str = "input",
) -> ScorerInvokeRecord | None:
"""Translate a generic Agent Control step into Orbit's record contract.

Expand All @@ -297,21 +303,30 @@ def _orbit_record_from_step(
Returns:
An Orbit-compatible record, or ``None`` for absent/unsupported steps.
"""
if step is None or step.type not in SUPPORTED_SCORER_INVOKE_RECORD_TYPES:
if step is None:
return None

# The membership check above narrows the runtime value to Orbit's known
# discriminator set, but static type checkers cannot infer that relationship.
record_type = cast(ScorerInvokeRecordType, step.type)
return ScorerInvokeRecord(
type=record_type,
name=step.name,
input=selected_input if selected_input is not None else step.input,
output=selected_output if selected_output is not None else step.output,
context=step.context,
tools=step.tools,
dataset_output=step.ground_truth,
)
try:
if selected_data is _MISSING_SELECTED_DATA:
galileo_core_record = record_from_step(
step,
selected_input=selected_input,
selected_output=selected_output,
)
else:
galileo_core_record = record_from_step(
step,
selected_data=selected_data,
payload_field=payload_field,
)
except UnsupportedStepTypeError:
return None
# record_from_step() returns Galileo Core models (LlmSpan, Trace, etc.). Dumping
# and revalidating coerces the model into the Luna request shape while preserving
# extra canonical fields that Orbit accepts but ScorerInvokeRecord does not declare.
canonical_record = galileo_core_record.model_dump(mode="json", exclude_none=True)
if canonical_record.get("type") not in SUPPORTED_SCORER_INVOKE_RECORD_TYPES:
return None
return ScorerInvokeRecord.model_validate(canonical_record)


class ScorerInvokeResponse(BaseModel):
Expand Down Expand Up @@ -487,6 +502,8 @@ async def invoke(
input: JSONValue = None,
output: JSONValue = None,
step: Step | None = None,
selected_data: Any = _MISSING_SELECTED_DATA,
selected_data_payload_field: str = "input",
execution_context: GalileoExecutionContext | None = None,
config: ScorerInvokeConfig | JSONObject | None = None,
timeout: float = DEFAULT_TIMEOUT_SECS,
Expand All @@ -502,6 +519,9 @@ async def invoke(
input: Optional user/system prompt text.
output: Optional model response text.
step: Optional complete runtime step used for structured dual-write.
selected_data: Raw selector-selected value used to construct the record,
preserving its structure independently from serialized legacy inputs.
selected_data_payload_field: Record input/output side for scalar selector values.
execution_context: Optional authenticated Galileo scorer context.
config: Optional Orbit-supported scorer invocation configuration.
timeout: Request timeout in seconds.
Expand Down Expand Up @@ -531,6 +551,17 @@ async def invoke(
invoke_config,
http_timeout_seconds=timeout,
)
record = (
_scorer_invoke_record_from_step(
step,
selected_input=input,
selected_output=output,
selected_data=selected_data,
payload_field=selected_data_payload_field,
)
if step is not None and scorer_version_id is not None
else None
)
request_body = ScorerInvokeRequest(
scorer_id=scorer_id,
scorer_version_id=scorer_version_id,
Expand All @@ -541,11 +572,7 @@ async def invoke(
ground_truth=step.ground_truth if step is not None else None,
tools=step.tools if step is not None else None,
),
record=_orbit_record_from_step(
step,
selected_input=input,
selected_output=output,
),
record=record,
execution_context=execution_context,
config=invoke_config,
).to_dict()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ class LunaEvaluatorConfig(EvaluatorConfig):

Attributes:
scorer_id: Required scorer identifier for Luna scorer invocation.
scorer_version_id: Deprecated optional compatibility identifier. Orbit
currently invokes the scorer's current default version.
scorer_version_id: Optional for legacy requests; required when the
contextual evaluator sends a structured record.
scorer_label: Optional display/metadata label.
threshold: Local threshold used by the evaluator for comparison.
operator: Local comparison operator. Numeric operators use threshold as a number.
Expand All @@ -75,8 +75,8 @@ class LunaEvaluatorConfig(EvaluatorConfig):
default=None,
min_length=1,
description=(
"Deprecated optional compatibility identifier. Orbit currently invokes "
"the scorer's current default version."
"Optional for legacy requests and required when contextual evaluation "
"sends a structured record."
),
)
scorer_label: str | None = Field(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ async def _evaluate(
scorer_kwargs = self._scorer_kwargs()
if step is not None:
scorer_kwargs["step"] = step
scorer_kwargs["selected_data"] = data
scorer_kwargs["selected_data_payload_field"] = self.config.payload_field
if execution_context is not None:
scorer_kwargs["execution_context"] = execution_context
response = await self._get_client().invoke(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
UnsupportedStepTypeError,
build_galileo_record,
build_record,
record_from_scorer_invoke_record,
record_from_step,
)
from .normalization import GalileoRecordNormalizer
Expand All @@ -18,6 +17,5 @@
"UnsupportedStepTypeError",
"build_galileo_record",
"build_record",
"record_from_scorer_invoke_record",
"record_from_step",
]
Loading
Loading