Skip to main content

lattice_ai/
install.rs

1//! AI-1b / AG‑4: the crate-owned `install(boot)` entry point.
2//!
3//! After the AG‑4 fold, `lattice-ai` owns both agent transports, so the
4//! single host-facing `lattice_ai::install(&mut boot)` line wires **both**:
5//! the ACP agent client (`install_acp`, below) and the MCP IDE peer
6//! (`crate::mcp::install`). The host's Phase-B install list holds one line
7//! and zero host internals (no `Editor::` method, no host `Effect`/`Action`
8//! variant, no `Editor` field for the logger). AG‑5 relocates `install_acp`
9//! under `crate::acp` and puts each call behind its `#[cfg(feature = …)]`.
10//!
11//! The `:ai-log` picker that OPENS a buffer is a later task; `install_acp`
12//! only wires the producer side (`AiLogger`), the supervisor, the ex-commands,
13//! and `AiLogMode` (which seeds/streams into a buffer once one is opened by
14//! name).
15
16use std::sync::Arc;
17
18use lattice_config::ConfigRegistry;
19use lattice_mode::SubsystemBoot;
20
21use lattice_agent::{AiLogLevel, AiLogMode, AiLogger};
22
23use crate::commands::register_ai_log_command;
24
25/// Wire the AI subsystem into the editor at boot. The transport-neutral log
26/// substrate (`AiLogger` + `AiLogMode` + `:ai-log`) is always installed; each
27/// agent transport is wired only when its feature is enabled.
28pub fn install(boot: &mut impl SubsystemBoot) {
29    let logger = install_ai_log(boot);
30
31    // The v1 opencode integration: `:opencode` runs opencode's TUI in a
32    // terminal buffer. Always wired (no transport feature) -- it's the primary
33    // opencode experience. The `acp` adapter below is the alternative
34    // buffer-conversation path (`:opencode-acp`).
35    crate::opencode::install(boot);
36
37    // The v1 pi integration: `:pi` runs pi's TUI in a terminal buffer.
38    // Always wired (no transport feature) -- same policy as opencode.
39    crate::pi::install(boot);
40
41    #[cfg(feature = "acp")]
42    crate::acp::install::install(boot, &logger);
43
44    #[cfg(feature = "mcp")]
45    crate::mcp::install::install(boot);
46
47    // `AiLogger` is a port-level service (`AiLogMode`'s `on_activate` reads it
48    // via `ctx.service::<AiLogger>()`, as does the `:ai-log` picker) -- register
49    // it regardless of which transport(s) produce records. This consumes the
50    // logger; the ACP supervisor above took a clone.
51    boot.register_service::<AiLogger>(logger);
52}
53
54/// Port-level: construct the `AiLogger` (seeded from the `ai.*` config options,
55/// registered Phase-A before this Phase-B `install` runs), wire its event
56/// publisher, register the `AiLogMode` major, and register the transport-neutral
57/// `:ai-log` command. Returns the logger for the ACP supervisor to clone.
58fn install_ai_log(boot: &mut impl SubsystemBoot) -> AiLogger {
59    let logger = AiLogger::with_defaults();
60    if let Some(config) = boot.service::<Arc<ConfigRegistry>>() {
61        // ai.log_level -> default min level.
62        if let Some(level_str) = config.get_typed::<lattice_config::core_options::AiLogLevel>()
63            && let Some(level) = AiLogLevel::parse(&level_str)
64        {
65            logger.set_default_level(level);
66        }
67        // ai.log = false -> disable capture (cap-0 rings drop every record).
68        if let Some(enabled) = config.get_typed::<lattice_config::core_options::AiLog>()
69            && !*enabled
70        {
71            logger.set_default_capacity(0);
72        }
73    }
74
75    // Publisher: every append -> runtime bus (AiLogMode's drain task subscribes
76    // to refresh open `*ai:<provider>:<index>*` buffers).
77    let bus = boot.event_bus().clone();
78    logger.set_event_publisher(Arc::new(move |event| bus.publish_typed(event)));
79
80    // Register the AiLogMode major (mirrors `register_lsp_log_modes`).
81    boot.modes_mut()
82        .register(AiLogMode)
83        .expect("ai-log-mode register");
84
85    // The transport-neutral `:ai-log` command (no ACP handle needed).
86    register_ai_log_command(boot.commands_mut());
87
88    logger
89}