mirror of
https://github.com/azaion/autopilot.git
synced 2026-06-22 16:51:10 +00:00
[AZ-643] [AZ-665] [AZ-672] mavlink+mapobjects+vlm batch 4
ci/woodpecker/push/build-arm Pipeline failed
ci/woodpecker/push/build-arm Pipeline failed
AZ-643 mavlink_layer:
- ack demux on COMMAND_LONG/COMMAND_ACK with oneshot dispatch and
configurable deadline; MavlinkHandle::send_command + SendCommandError
- MAVLink-2 signing: Signer/Verifier built on SHA-256, key + timestamp
source, incompat-flag wiring in encoder, reject + counter in decoder
- new tests: tests/ack_demux.rs (3) + tests/signing.rs (5)
AZ-665 mapobjects_store:
- internal/h3_index.rs (h3o wrapper, cell_of, grid_disk, haversine)
- internal/store.rs (in-memory (cell -> Vec<MapObject>) hashmap with
k-ring classify and class-group resolution)
- public API: MapObjectsStoreHandle::classify(ClassifyInput) ->
Classification {New|Moved|Existing}
- AC1-4 in tests/classify.rs; AC5 perf gate (#[ignore], passes in
--release)
AZ-672 vlm_client + autopilot:
- DisabledVlmProvider in shared::contracts; VlmProvider::name() for
composition-root diagnostics
- vlm_client::VlmClient gated behind feature = "vlm"; placeholder
until AZ-673 lands the real NanoLLM IPC
- autopilot: vlm_client is now optional = true under feature vlm;
Runtime::select_vlm_provider picks DisabledVlmProvider when feature
off OR config.vlm.enabled = false
Workspace deps: +sha2 (mavlink signing), +h3o (mapobjects index).
Batch report: _docs/03_implementation/batch_04_cycle1_report.md
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
//! Feature-gated entry point. Compiled only when `--features vlm` is on.
|
||||
//!
|
||||
//! AZ-672 installs the trait + a placeholder constructor; the real IPC
|
||||
//! body lands in AZ-673 (`vlm_client_nanollm_ipc`). Until then `assess`
|
||||
//! returns `VlmAssessment::disabled()` so the runtime can be wired
|
||||
//! end-to-end without a working NanoLLM peer.
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use shared::contracts::VlmProvider;
|
||||
use shared::error::Result;
|
||||
use shared::health::ComponentHealth;
|
||||
use shared::models::vlm::VlmAssessment;
|
||||
|
||||
use super::PROVIDER_NAME;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VlmClient {
|
||||
ipc_socket: String,
|
||||
}
|
||||
|
||||
impl VlmClient {
|
||||
/// Construct the feature-enabled client. Until AZ-673 lands, the
|
||||
/// returned instance still answers `assess` with the disabled
|
||||
/// no-op assessment — the difference vs `DisabledVlmProvider` is
|
||||
/// that this socket address has been validated and the IPC
|
||||
/// connection will be established here in AZ-673.
|
||||
pub fn new(ipc_socket: impl Into<String>) -> Self {
|
||||
Self {
|
||||
ipc_socket: ipc_socket.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ipc_socket(&self) -> &str {
|
||||
&self.ipc_socket
|
||||
}
|
||||
|
||||
pub fn health(&self) -> ComponentHealth {
|
||||
// Until AZ-673 connects, we surface yellow with the configured
|
||||
// socket so the operator sees the build *did* enable VLM but
|
||||
// the IPC peer is not yet wired.
|
||||
ComponentHealth::yellow(PROVIDER_NAME, format!("ipc_pending: {}", self.ipc_socket))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl VlmProvider for VlmClient {
|
||||
async fn assess(&self, _roi: Vec<u8>, _prompt: String) -> Result<VlmAssessment> {
|
||||
// Real IPC call lands in AZ-673. Returning disabled keeps the
|
||||
// runtime end-to-end exercisable until that task completes.
|
||||
Ok(VlmAssessment::disabled())
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
PROVIDER_NAME
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use shared::models::vlm::VlmStatus;
|
||||
|
||||
#[tokio::test]
|
||||
async fn placeholder_assess_returns_disabled_until_az_673() {
|
||||
// Arrange
|
||||
let c = VlmClient::new("/run/vila/ipc.sock");
|
||||
// Act
|
||||
let r = c
|
||||
.assess(Vec::new(), String::new())
|
||||
.await
|
||||
.expect("placeholder path is infallible");
|
||||
// Assert
|
||||
assert_eq!(r.status, VlmStatus::Disabled);
|
||||
assert_eq!(c.name(), "vlm_client");
|
||||
assert_eq!(c.ipc_socket(), "/run/vila/ipc.sock");
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,23 @@
|
||||
//! `vlm_client` — optional Tier 3 NanoLLM/VILA Visual-Language-Model client.
|
||||
//!
|
||||
//! Default impl (`feature = "vlm"` OFF) returns `VlmAssessment::disabled()`.
|
||||
//! Real IPC path lands in:
|
||||
//! - AZ-672 `vlm_client_provider_trait`
|
||||
//! With the `vlm` Cargo feature **off**, this crate exports nothing
|
||||
//! beyond a constant noting the disabled state. The composition root
|
||||
//! installs `shared::contracts::DisabledVlmProvider` in that case and
|
||||
//! never references `vlm_client::VlmClient`.
|
||||
//!
|
||||
//! With the `vlm` feature **on**, `VlmClient` is the real NanoLLM IPC
|
||||
//! client. The IPC plumbing itself lands in:
|
||||
//! - AZ-673 `vlm_client_nanollm_ipc`
|
||||
//! - AZ-674 `vlm_client_schema_and_model_version`
|
||||
//!
|
||||
//! AZ-672 only wires the trait contract + feature flag.
|
||||
|
||||
use async_trait::async_trait;
|
||||
#[cfg(feature = "vlm")]
|
||||
mod enabled;
|
||||
|
||||
use shared::contracts::VlmProvider;
|
||||
use shared::error::Result;
|
||||
use shared::health::ComponentHealth;
|
||||
use shared::models::vlm::VlmAssessment;
|
||||
#[cfg(feature = "vlm")]
|
||||
pub use enabled::VlmClient;
|
||||
|
||||
const NAME: &str = "vlm_client";
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct VlmClient {
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
impl VlmClient {
|
||||
/// Construct the no-op `VlmClient`. Returns `VlmAssessment::disabled()`
|
||||
/// from every `assess()` call.
|
||||
pub fn with_default() -> Self {
|
||||
Self { enabled: false }
|
||||
}
|
||||
|
||||
#[cfg(feature = "vlm")]
|
||||
pub fn enabled() -> Self {
|
||||
Self { enabled: true }
|
||||
}
|
||||
|
||||
pub fn health(&self) -> ComponentHealth {
|
||||
if self.enabled {
|
||||
ComponentHealth::green(NAME)
|
||||
} else {
|
||||
ComponentHealth::disabled(NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl VlmProvider for VlmClient {
|
||||
async fn assess(&self, _roi: Vec<u8>, _prompt: String) -> Result<VlmAssessment> {
|
||||
// Disabled path always returns the documented no-op assessment.
|
||||
// The real path lands in AZ-673.
|
||||
Ok(VlmAssessment::disabled())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn default_impl_returns_disabled_assessment() {
|
||||
// Arrange
|
||||
let c = VlmClient::with_default();
|
||||
|
||||
// Act
|
||||
let result = c
|
||||
.assess(Vec::new(), String::new())
|
||||
.await
|
||||
.expect("disabled path is infallible");
|
||||
|
||||
// Assert
|
||||
assert_eq!(result.status, shared::models::vlm::VlmStatus::Disabled);
|
||||
assert_eq!(result.label, shared::models::vlm::VlmLabel::Inconclusive);
|
||||
}
|
||||
}
|
||||
/// Stable name used by tracing + `/health` to identify this crate's
|
||||
/// build-time configuration. Mirrors `VlmProvider::name()`.
|
||||
pub const PROVIDER_NAME: &str = "vlm_client";
|
||||
|
||||
Reference in New Issue
Block a user