commit df47222d6a7c5aa8528d4f759860661f733d6002
parent 3a33491efce98e7a2510fc7e6abbe0026b335a6d
Author: triesap <tyson@radroots.org>
Date: Mon, 21 Sep 2026 13:04:32 +0000
provider: implement jev request serialization
Diffstat:
3 files changed, 84 insertions(+), 0 deletions(-)
diff --git a/pixi.toml b/pixi.toml
@@ -26,6 +26,7 @@ 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-jev = "mojo -I src -I tests tests/test_jev.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"
@@ -40,6 +41,7 @@ test = { depends-on = [
"test-unit",
"test-domain",
"test-assist",
+ "test-jev",
"test-provider-adapter",
"test-spec",
"test-architecture",
diff --git a/src/hyf_provider/jev_request.mojo b/src/hyf_provider/jev_request.mojo
@@ -0,0 +1,37 @@
+from json import Value, loads
+
+from hyf_assist.questions import Question, QuestionBundle
+
+
+def _choice_criteria(question: Question) raises -> Value:
+ var criteria = loads("{}")
+ for choice in question.choices:
+ criteria.set(String(choice), Value(None))
+ return criteria^
+
+
+def _score_criteria(question: Question) raises -> Value:
+ var criteria = loads("[]")
+ for level in question.rubric:
+ criteria.append(Value(String(level)))
+ return criteria^
+
+
+def build_jev_request_body(bundle: QuestionBundle, state: String) raises -> Value:
+ if state.strip() == "":
+ raise Error("jev request requires non-empty state")
+ var body = loads("{}")
+ body.set("model", Value(String(bundle.model)))
+ body.set("state", Value(String(state)))
+ var questions = loads("{}")
+ for question in bundle.questions:
+ var value = loads("{}")
+ value.set("type", Value(String(question.kind)))
+ value.set("instructions", Value(String(question.instructions)))
+ if question.kind == "choice":
+ value.set("criteria", _choice_criteria(question))
+ elif question.kind == "score":
+ value.set("criteria", _score_criteria(question))
+ questions.set(String(question.id), value)
+ body.set("questions", questions)
+ return body^
diff --git a/tests/test_jev.mojo b/tests/test_jev.mojo
@@ -0,0 +1,45 @@
+from std.collections import List
+from std.testing import TestSuite, assert_equal, assert_raises, assert_true
+
+from hyf_assist.questions import (
+ Question,
+ QuestionBundle,
+ choice_question,
+ noul_question,
+ question_bundle,
+ score_question,
+)
+from hyf_provider.jev_request import build_jev_request_body
+
+
+def _bundle() raises -> QuestionBundle:
+ var choices = List[String]()
+ choices.append("offered")
+ choices.append("forecast")
+ choices.append("unclear")
+ var questions = List[Question]()
+ questions.append(choice_question("supply_status", "status?", choices))
+ questions.append(noul_question("seconds_ok", "seconds?"))
+ var rubric = List[String]()
+ rubric.append("unsuitable")
+ rubric.append("limited")
+ rubric.append("suitable")
+ questions.append(score_question("culinary_fit", "fit?", rubric))
+ return question_bundle("qb1", "1", "jev-1.13.0", questions)
+
+
+def test_jev_request_serialization_shape() raises:
+ var body = build_jev_request_body(_bundle(), "Roma tomatoes available now")
+ assert_equal(body["model"].string_value(), "jev-1.13.0")
+ assert_equal(body["state"].string_value(), "Roma tomatoes available now")
+ assert_equal(body["questions"]["supply_status"]["type"].string_value(), "choice")
+ assert_true(body["questions"]["supply_status"]["criteria"]["offered"].is_null())
+ assert_equal(body["questions"]["seconds_ok"]["type"].string_value(), "noul")
+ assert_equal(body["questions"]["culinary_fit"]["type"].string_value(), "score")
+ assert_equal(len(body["questions"]["culinary_fit"]["criteria"].array_items()), 3)
+ with assert_raises():
+ _ = build_jev_request_body(_bundle(), "")
+
+
+def main() raises:
+ TestSuite.discover_tests[__functions_in_module()]().run()