///|
/// Guest entry point: greet the host, take the invoke frame, run the guest
/// program once, and emit the result frame. A raised `Failure::Failure`
/// becomes a failure result; other errors propagate to the runtime.
pub async fn serve(wire~ : &Wire, run~ : async (Ears, Json) -> Json) -> Unit {
wire.send("{\"type\":\"hello\",\"protocol\":1}\n")
guard wire.receive() is Some(line) else {
fail("ears: host disconnected before the invoke frame")
}
let frame = @json.parse(line) catch {
_ => fail("ears: invoke frame is not valid JSON")
}
guard frame
is { "type": "invoke", "input": input, "tools": Array(raw_tools), .. } else {
fail("ears: invalid host invoke frame")
}
let allowed = []
for tool in raw_tools {
if tool is String(name) {
allowed.push(name)
}
}
let ears = Ears::Ears(wire~, allowed~)
let outcome : Outcome = try {
let value = run(ears, input)
Outcome::Success(content=value.stringify(), structured=Some(value))
} catch {
Failure::Failure(message) =>
Outcome::Failure(code="GuestFailed", content=message, structured=None)
error => raise error
}
ears.close()
let result : Json = { "type": "result", "outcome": outcome.to_json() }
wire.send(result.stringify() + "\n")
}