sim_lib_bridge/
frontier.rs1use std::sync::Arc;
2
3use sim_codec_bridge::{BridgeBook, BridgeFramePayload, BridgePacket};
4use sim_kernel::{Cx, Expr, Result, Symbol};
5use sim_lib_agent_runner_core::shape_to_grammar;
6use sim_shape::{ExactExprShape, OneOfShape, Shape};
7use sim_value::build::entry;
8
9pub struct FrontierMenu {
11 pub slots: Vec<(String, Expr)>,
13 pub heads: Expr,
15 pub head_shape: Arc<dyn Shape>,
17 pub grammar: String,
19}
20
21pub fn frontier(_cx: &mut Cx, packet: &BridgePacket) -> Result<FrontierMenu> {
23 let book = BridgeBook::standard();
24 let slots = frame_slots(&book, packet)?;
25 let heads = book
26 .moves
27 .legal_reply_intents(std::slice::from_ref(&packet.header.move_kind));
28 let head_shape = OneOfShape::new(
29 heads
30 .iter()
31 .map(|head| Arc::new(ExactExprShape::new(Expr::Symbol(head.clone()))) as Arc<dyn Shape>)
32 .collect(),
33 );
34 let grammar = shape_to_grammar(&head_shape)?;
35 Ok(FrontierMenu {
36 slots,
37 heads: Expr::Map(vec![
38 entry("shape", Expr::Symbol(Symbol::qualified("shape", "OneOf"))),
39 entry(
40 "choices",
41 Expr::Vector(heads.into_iter().map(Expr::Symbol).collect()),
42 ),
43 ]),
44 head_shape: Arc::new(head_shape),
45 grammar,
46 })
47}
48
49fn frame_slots(book: &BridgeBook, packet: &BridgePacket) -> Result<Vec<(String, Expr)>> {
50 let mut slots = Vec::new();
51 for part in &packet.body {
52 if part.kind != Symbol::qualified("bridge", "Frame") {
53 continue;
54 }
55 let payload = BridgeFramePayload::from_expr(&part.payload)?;
56 let spec = book.frames.require_spec(&payload.frame)?;
57 for hole in &spec.holes {
58 slots.push((
59 format!(
60 "{}.{}",
61 part.id.as_qualified_str(),
62 hole.name.as_qualified_str()
63 ),
64 hole.kind.shape_expr(),
65 ));
66 }
67 }
68 Ok(slots)
69}