Skip to main content

sim_lib_bridge/
frontier.rs

1use 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
9/// Legal next heads plus in-scope slot shapes for a BRIDGE packet.
10pub struct FrontierMenu {
11    /// Slot id to shape descriptor.
12    pub slots: Vec<(String, Expr)>,
13    /// Flat `OneOf` descriptor for legal next move heads.
14    pub heads: Expr,
15    /// Grammar lowered from the same flat `OneOf`.
16    pub grammar: String,
17}
18
19/// Computes the shared BRIDGE frontier for BRIEF, ASK, LOOM, and COLLAB views.
20pub fn frontier(_cx: &mut Cx, packet: &BridgePacket) -> Result<FrontierMenu> {
21    let book = BridgeBook::standard();
22    let slots = frame_slots(&book, packet)?;
23    let heads = book
24        .moves
25        .legal_reply_intents(std::slice::from_ref(&packet.header.move_kind));
26    let head_shape = OneOfShape::new(
27        heads
28            .iter()
29            .map(|head| Arc::new(ExactExprShape::new(Expr::Symbol(head.clone()))) as Arc<dyn Shape>)
30            .collect(),
31    );
32    let grammar = shape_to_grammar(&head_shape)?;
33    Ok(FrontierMenu {
34        slots,
35        heads: Expr::Map(vec![
36            entry("shape", Expr::Symbol(Symbol::qualified("shape", "OneOf"))),
37            entry(
38                "choices",
39                Expr::Vector(heads.into_iter().map(Expr::Symbol).collect()),
40            ),
41        ]),
42        grammar,
43    })
44}
45
46fn frame_slots(book: &BridgeBook, packet: &BridgePacket) -> Result<Vec<(String, Expr)>> {
47    let mut slots = Vec::new();
48    for part in &packet.body {
49        if part.kind != Symbol::qualified("bridge", "Frame") {
50            continue;
51        }
52        let payload = BridgeFramePayload::from_expr(&part.payload)?;
53        let spec = book.frames.require_spec(&payload.frame)?;
54        for hole in &spec.holes {
55            slots.push((
56                format!(
57                    "{}.{}",
58                    part.id.as_qualified_str(),
59                    hole.name.as_qualified_str()
60                ),
61                hole.kind.shape_expr(),
62            ));
63        }
64    }
65    Ok(slots)
66}