hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

commit ee0915aef8fa778ebb3e527397a2b3fa14d17840
parent d842040d71c4533872979a220a02f1fbbfcbaffd
Author: triesap <tyson@radroots.org>
Date:   Mon, 21 Sep 2026 13:02:51 +0000

core: define the narrow semantic evaluator boundary

Diffstat:
Mpixi.toml | 2++
Asrc/hyf_assist/evaluator.mojo | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/test_assist.mojo | 46++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 138 insertions(+), 0 deletions(-)

diff --git a/pixi.toml b/pixi.toml @@ -25,6 +25,7 @@ test-repo-local-process = "mojo -I src tests/test_repo_local_process_contract.mo test-stdio = "mojo -I src tests/test_stdio_contract.mojo" test-provider-adapter = "mojo -I src -I tests tests/test_provider_adapter.mojo" test-domain = "mojo -I src -I tests tests/test_domain.mojo" +test-assist = "mojo -I src -I tests tests/test_assist.mojo" test-spec = "mojo -I src -I tests tests/test_traceability.mojo" check-build = "mkdir -p .pixi/build && mojo build -I src src/main.mojo -o .pixi/build/hyfd" check-format = "sh tools/check_format.sh" @@ -38,6 +39,7 @@ test-runtime-contract = { depends-on = [ test = { depends-on = [ "test-unit", "test-domain", + "test-assist", "test-provider-adapter", "test-spec", "test-architecture", diff --git a/src/hyf_assist/evaluator.mojo b/src/hyf_assist/evaluator.mojo @@ -0,0 +1,90 @@ +from std.collections import List + + +@fieldwise_init +struct TypedAnswer(Copyable, Movable): + var question_id: String + var kind: String + var choice: String + var score: Int + var noul: Float64 + var confidence: Float64 + + +@fieldwise_init +struct SemanticEvaluatorRequest(Copyable, Movable): + var state: String + var question_bundle: String + + +@fieldwise_init +struct SemanticEvaluatorResponse(Copyable, Movable): + var model: String + var answers: List[TypedAnswer] + + +@fieldwise_init +struct DisabledSemanticEvaluator(Copyable, Movable): + def evaluate( + self, request: SemanticEvaluatorRequest + ) raises -> SemanticEvaluatorResponse: + raise Error("semantic evaluator is disabled") + + +def typed_choice( + question_id: String, choice: String, confidence: Float64 +) raises -> TypedAnswer: + if question_id.strip() == "" or choice.strip() == "": + raise Error("choice answer requires question id and choice") + if confidence < 0.0 or confidence > 1.0: + raise Error("choice confidence must be within [0, 1]") + return TypedAnswer( + question_id=String(question_id), + kind="choice", + choice=String(choice), + score=0, + noul=0.0, + confidence=confidence, + ) + + +def typed_noul(question_id: String, noul: Float64) raises -> TypedAnswer: + if noul < 0.0 or noul > 1.0: + raise Error("noul probability must be within [0, 1]") + return TypedAnswer( + question_id=String(question_id), + kind="noul", + choice="", + score=0, + noul=noul, + confidence=noul, + ) + + +def typed_score( + question_id: String, score: Int, levels: Int, confidence: Float64 +) raises -> TypedAnswer: + if levels < 2: + raise Error("score rubric requires at least two levels") + if score < 0 or score >= levels: + raise Error("score is out of rubric range") + if confidence < 0.0 or confidence > 1.0: + raise Error("score confidence must be within [0, 1]") + return TypedAnswer( + question_id=String(question_id), + kind="score", + choice="", + score=score, + noul=0.0, + confidence=confidence, + ) + + +def normalize_score(answer: TypedAnswer, levels: Int) raises -> Float64: + if answer.kind != "score": + raise Error("normalize_score requires a score answer") + if levels < 2: + raise Error("score rubric requires at least two levels") + if answer.score < 0 or answer.score >= levels: + raise Error("score is out of rubric range") + return Float64(answer.score) / Float64(levels - 1) diff --git a/tests/test_assist.mojo b/tests/test_assist.mojo @@ -0,0 +1,46 @@ +from std.collections import List +from std.testing import TestSuite, assert_equal, assert_raises, assert_true + +from hyf_assist.evaluator import ( + DisabledSemanticEvaluator, + SemanticEvaluatorRequest, + SemanticEvaluatorResponse, + TypedAnswer, + normalize_score, + typed_choice, + typed_noul, + typed_score, +) + + +def test_evaluator_boundary_is_typed_and_scriptable() raises: + var answers = List[TypedAnswer]() + answers.append(typed_choice("supply_status", "offered", 1.0)) + var response = SemanticEvaluatorResponse(model="test-model", answers=answers^) + assert_equal(response.model, "test-model") + assert_equal(len(response.answers), 1) + assert_equal(response.answers[0].kind, "choice") + assert_equal(response.answers[0].choice, "offered") + + var disabled = DisabledSemanticEvaluator() + with assert_raises(): + _ = disabled.evaluate( + SemanticEvaluatorRequest(state="s", question_bundle="q") + ) + + +def test_typed_answers_and_score_normalization() raises: + assert_equal(typed_noul("q", 0.5).kind, "noul") + assert_equal(typed_score("s", 2, 3, 1.0).score, 2) + assert_equal(normalize_score(typed_score("s", 2, 3, 1.0), 3), 1.0) + assert_equal(normalize_score(typed_score("s", 1, 3, 1.0), 3), 0.5) + with assert_raises(): + _ = typed_choice("q", "x", 1.5) + with assert_raises(): + _ = typed_noul("q", -0.1) + with assert_raises(): + _ = typed_score("s", 5, 3, 1.0) + + +def main() raises: + TestSuite.discover_tests[__functions_in_module()]().run()