Verse command: a lane that cannot open names the flag or fault kind, never the endpoint
open_inference's error was wrapped with .context and printed through the anyhow chain, so a refused non-loopback --base-url put the operator's address on stderr. lane_fault maps each ControllerOpenError variant to one fixed message; ControllerOpenError is exported for it. Fixes local-endpoint-echoed. Builds; the workspace is unchanged elsewhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5cf005eb2c
commit
2a888da955
3 changed files with 56 additions and 4 deletions
|
|
@ -9,10 +9,10 @@
|
|||
//! `calls.cc`. The provider key is read from a file at run time and appears
|
||||
//! nowhere else.
|
||||
|
||||
use anyhow::{Context, Result, bail};
|
||||
use anyhow::{Context, Result, anyhow, bail};
|
||||
use chrono::{Duration, Utc};
|
||||
use ghostlight::{
|
||||
CommandBody, CommandId, ControllerModels, ControllerRunner, DEFAULT_HOSTED_MODEL_PREFIX,
|
||||
CommandBody, CommandId, ControllerModels, ControllerOpenError, ControllerRunner, DEFAULT_HOSTED_MODEL_PREFIX,
|
||||
DEFAULT_LOCAL_MODEL_PREFIX, CallRecordStore, CoverBudget, CreateVerseWorldIntent,
|
||||
HostedBinding, Lens, LensWeights, LocalBinding, PrincipalCommandIntent, RecordingInferencePort,
|
||||
RunStart, RunStatus, TickMinutes, VerifiedPrincipalEvidence, VerseRunConfig, VerseRunStore,
|
||||
|
|
@ -290,5 +290,29 @@ fn open_lane(
|
|||
bail!("--model names no inference lane (expected a hosted/ or local/ prefix)");
|
||||
}
|
||||
open_inference(None, None, local, hosted, &models.each())
|
||||
.context("the inference lane cannot open")
|
||||
.map_err(|error| anyhow!(lane_fault(&error)))
|
||||
}
|
||||
|
||||
/// What a lane that cannot open says: the flag or the kind of fault, never a
|
||||
/// value the operator passed.
|
||||
fn lane_fault(error: &ControllerOpenError) -> &'static str {
|
||||
match error {
|
||||
ControllerOpenError::InvalidModels => "--model is not an exact nonempty identifier",
|
||||
ControllerOpenError::Connector(_) => "the connector lane cannot open",
|
||||
ControllerOpenError::WorkStore(_) => "the controller work journal cannot open",
|
||||
ControllerOpenError::UnroutableModel { .. } => "--model is claimed by no inference lane",
|
||||
ControllerOpenError::SdkSidecarMissing { .. } => "the SDK sidecar entry is not a file",
|
||||
ControllerOpenError::LocalEndpointNotLoopback { .. } => {
|
||||
"--base-url for a local model must be a loopback address"
|
||||
}
|
||||
ControllerOpenError::HostedEndpointNotHttps => {
|
||||
"--base-url for a hosted model must be an https URL"
|
||||
}
|
||||
ControllerOpenError::HostedKeyUnreadable => {
|
||||
"--key-file is unreadable, empty, or not one run of visible ASCII"
|
||||
}
|
||||
ControllerOpenError::SharedModelPrefix { .. } => "two inference lanes claim one model prefix",
|
||||
ControllerOpenError::EmptyModelPrefix { .. } => "an inference lane's model prefix is empty",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ fn the_command_refuses_what_it_cannot_run_and_never_echoes_a_value() {
|
|||
"--token-cap", "1", "--tick-span-minutes", "60", "--model", "hosted/x",
|
||||
"--base-url", "https://api.example.test", "--key-file", key.to_str().unwrap(),
|
||||
],
|
||||
"the inference lane cannot open",
|
||||
"--key-file is unreadable",
|
||||
),
|
||||
(
|
||||
vec![
|
||||
|
|
@ -332,3 +332,30 @@ fn the_command_refuses_what_it_cannot_run_and_never_echoes_a_value() {
|
|||
assert!(!error.contains("many"), "{arguments:?} echoed a value: {error}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_non_loopback_local_endpoint_is_refused_without_echoing_it() {
|
||||
let state = tempfile::tempdir().unwrap();
|
||||
assert!(genesis(state.path()).status.success());
|
||||
let output = verse(&[
|
||||
"run",
|
||||
"--state",
|
||||
state.path().to_str().unwrap(),
|
||||
"--ticks",
|
||||
"1",
|
||||
"--token-cap",
|
||||
"1000",
|
||||
"--tick-span-minutes",
|
||||
"60",
|
||||
"--model",
|
||||
"local/x",
|
||||
"--base-url",
|
||||
"http://10.77.0.99:4242",
|
||||
]);
|
||||
assert!(!output.status.success());
|
||||
let error = stderr(&output);
|
||||
assert!(error.contains("--base-url"), "{error}");
|
||||
assert!(!error.contains("10.77.0.99"), "the endpoint was echoed: {error}");
|
||||
// The lane failed before any run was claimed.
|
||||
assert!(!stdout(&output).contains("run 1"), "{}", stdout(&output));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ pub use consumer::{
|
|||
};
|
||||
pub use controllers::{
|
||||
CONTROLLER_WORK_SCHEMA, CellRun, ConnectorBinding, ControllerError, ControllerModels,
|
||||
ControllerOpenError,
|
||||
ControllerNeed, ControllerPendingReason, ControllerRunner, ControllerWork,
|
||||
ControllerWorkCustody, ControllerWorkLookup, ControllerWorkStore, ControllerWorkStoreError,
|
||||
ControllerWorkWrite,
|
||||
|
|
|
|||
Loading…
Reference in a new issue