Move the operation envelope to huginn-mind: one spelling for client and daemon
envelope.rs (encode/decode request and response, OperationFailure, FAILURE_SCHEMA) leaves huginn-daemon for huginn-mind, next to the wire types it wraps. The daemon imports it and no longer re-exports it. base64 moves with it; the daemon keeps base64 because serve.rs measures and decodes payloads. schemars leaves the daemon, whose only user was the envelope's OperationFailure derive. The two envelope tests run unchanged from their new home on huginn-mind fixtures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ff39d80297
commit
debe7ce9e7
8 changed files with 23 additions and 21 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -477,7 +477,6 @@ dependencies = [
|
|||
"cultnet-rs",
|
||||
"huginn-mind",
|
||||
"rmp-serde",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
|
@ -491,6 +490,7 @@ name = "huginn-mind"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"chrono",
|
||||
"cultcache-rs",
|
||||
"cultnet-rs",
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ chrono = "0.4.44"
|
|||
cultnet-rs = { git = "https://github.com/GameCult/CultLib.git", rev = "6251cbcd37c12ef3f0c1cc50063a03369225b7ac", package = "cultnet-rs" }
|
||||
huginn-mind = { path = "../huginn-mind" }
|
||||
rmp-serde = "1"
|
||||
schemars = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
# The vector store's and the embedder's HTTP APIs are the xenos boundary, and
|
||||
# JSON exists in `index/ollama.rs` and `index/qdrant.rs` only. `ureq` 3 with
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
//! `huginn-daemon`: one process that serves one mind over CultNet.
|
||||
//!
|
||||
//! The crate owns five things and no rule. `startup` owns "may this process
|
||||
//! The crate owns four things and no rule. `startup` owns "may this process
|
||||
//! serve this mind", by delegating to `Mind::open` and refusing before
|
||||
//! anything listens. `index` owns when the mind's documents are embedded and
|
||||
//! written to the vector store, off the serving path. `Daemon::handle` owns "which `Mind` method answers this
|
||||
//! request": it dispatches, it asks `Mind::require_instance` for every read
|
||||
//! that names an instance, and it compares nothing itself. `envelope` owns "is
|
||||
//! this a request at all": a message it cannot decode is answered with a typed
|
||||
//! failure and touches no mind. `serve` owns "which session gets which reply"
|
||||
//! and whether an answer is delivered whole, deferred or refused; `bodies`
|
||||
//! that names an instance, and it compares nothing itself. `serve` owns "which
|
||||
//! session gets which reply" and whether an answer is delivered whole, deferred or refused; `bodies`
|
||||
//! owns how long and how much of a deferred answer is held.
|
||||
//!
|
||||
//! Every admission rule, the instance check, the receipt, the derived status
|
||||
|
|
@ -17,7 +15,6 @@
|
|||
|
||||
pub mod bodies;
|
||||
pub mod daemon;
|
||||
pub mod envelope;
|
||||
pub mod index;
|
||||
pub mod serve;
|
||||
|
||||
|
|
@ -25,5 +22,4 @@ pub mod serve;
|
|||
mod semantic_tests;
|
||||
|
||||
pub use daemon::{Daemon, Handled, Hits, IndexSink, Search, SearchTicket, runtime_id};
|
||||
pub use envelope::{FAILURE_SCHEMA, OperationFailure};
|
||||
pub use serve::{Options, ServeOptions, parse_options, run, startup};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use tempfile::TempDir;
|
|||
|
||||
use crate::daemon::Daemon;
|
||||
use crate::daemon::tests::{CAMPAIGN, INSTANCE, batch, campaign_seed, now, slug};
|
||||
use crate::envelope::{decode_response, encode_request};
|
||||
use huginn_mind::envelope::{decode_response, encode_request};
|
||||
use crate::index::fakes::{FakeEmbedder, FakeIndex, Gate};
|
||||
use crate::index::{Backoff, Described, Hit, WorkerSink, collection_name};
|
||||
use crate::serve::{ServeOptions, bind, run, schema_registry};
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ use crate::bodies::{
|
|||
DEFERRED_BUDGET_BYTES, DEFERRED_CHUNK_BYTES, DeferredBodies, MAX_DEFERRED_BODY_BYTES,
|
||||
};
|
||||
use crate::daemon::{Daemon, Handled, IndexSink, Search, SearchTicket, runtime_id};
|
||||
use crate::envelope::{OperationFailure, decode_request, encode_failure, encode_response};
|
||||
use huginn_mind::envelope::{OperationFailure, decode_request, encode_failure, encode_response};
|
||||
use crate::index::{Backoff, Embedder, VectorIndex, WorkerSink};
|
||||
|
||||
/// What the loop does when nothing is waiting. A deferred body untouched for
|
||||
|
|
@ -345,7 +345,7 @@ fn encode_or_fail(
|
|||
Err(error) => encode_failure(
|
||||
message_id,
|
||||
operation,
|
||||
&crate::envelope::OperationFailure {
|
||||
&OperationFailure {
|
||||
code: "response-not-encodable".into(),
|
||||
message: format!("{error:#}"),
|
||||
},
|
||||
|
|
@ -548,7 +548,7 @@ mod tests {
|
|||
open_unindexed, seeded_wide, slug,
|
||||
};
|
||||
use huginn_mind::epiphany_pipeline::{PipelineKind, PipelineRef};
|
||||
use crate::envelope::{FAILURE_SCHEMA, decode_response, encode_request};
|
||||
use huginn_mind::envelope::{FAILURE_SCHEMA, decode_response, encode_request};
|
||||
use crate::index::Backoff;
|
||||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
|
|
@ -632,7 +632,7 @@ mod tests {
|
|||
assert_eq!(rejected(&reply).1, code);
|
||||
}
|
||||
// The sixth code, `not-an-operation-request`, is the codec's and is
|
||||
// pinned in `envelope::tests`: `answer` never produces it, because a
|
||||
// pinned in `huginn_mind::envelope::tests`: `answer` never produces it, because a
|
||||
// message of another family is answered with `Error` instead.
|
||||
let reply = answer(&mut daemon, ®istry, &mut fresh_bodies(), CultNetMessage::Error { error: "hello".into(), code: None, details: None }, now()).reply();
|
||||
let CultNetMessage::Error { error, .. } = &reply else { panic!("expected an error, got {reply:?}") };
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ publish.workspace = true
|
|||
# daemon's (Cut 10, Cut 11).
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
base64 = "0.22"
|
||||
chrono = "0.4.44"
|
||||
cultcache-rs = { git = "https://github.com/GameCult/CultLib.git", rev = "6251cbcd37c12ef3f0c1cc50063a03369225b7ac", package = "cultcache-rs" }
|
||||
cultnet-rs = { git = "https://github.com/GameCult/CultLib.git", rev = "6251cbcd37c12ef3f0c1cc50063a03369225b7ac", package = "cultnet-rs" }
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use anyhow::Result;
|
|||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use cultnet_rs::CultNetMessage;
|
||||
use huginn_mind::wire::{HuginnMindRequest, HuginnMindResponse, MIND_REQUEST_SCHEMA, MIND_RESPONSE_SCHEMA, MIND_SERVICE_ID};
|
||||
use crate::wire::{HuginnMindRequest, HuginnMindResponse, MIND_REQUEST_SCHEMA, MIND_RESPONSE_SCHEMA, MIND_SERVICE_ID};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -151,9 +151,9 @@ pub fn decode_response(message: &CultNetMessage) -> Result<(String, Result<Hugin
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::daemon::tests::{INSTANCE, OTHER, batch, identity, slug};
|
||||
use huginn_mind::wire::MindStatus;
|
||||
use huginn_mind::{MindRefusal, PipelineAdmissionOutcome};
|
||||
use crate::fixtures::{INSTANCE, OTHER_INSTANCE as OTHER, instance, provenance, slug};
|
||||
use crate::wire::MindStatus;
|
||||
use crate::{Faculty, MindRefusal, PipelineAdmissionBatch, PipelineAdmissionOutcome};
|
||||
|
||||
fn refusal() -> MindRefusal {
|
||||
MindRefusal::ForeignInstance { declared: OTHER.into(), mind: INSTANCE.into() }
|
||||
|
|
@ -183,7 +183,7 @@ mod tests {
|
|||
schema_epoch: "epiphany.pipeline.epoch.v2".into(),
|
||||
documents: 0,
|
||||
receipts: 0,
|
||||
index: huginn_mind::wire::IndexStatus::Current,
|
||||
index: crate::wire::IndexStatus::Current,
|
||||
}),
|
||||
"accepted",
|
||||
),
|
||||
|
|
@ -214,7 +214,11 @@ mod tests {
|
|||
/// `Error` instead.
|
||||
#[test]
|
||||
fn a_request_round_trips_and_a_foreign_message_is_not_a_request() {
|
||||
let request = HuginnMindRequest::Admit(batch(INSTANCE, vec![identity(INSTANCE)]));
|
||||
let request = HuginnMindRequest::Admit(PipelineAdmissionBatch {
|
||||
instance: slug(INSTANCE),
|
||||
provenance: provenance(Faculty::Hands),
|
||||
documents: vec![instance(INSTANCE)],
|
||||
});
|
||||
let message = encode_request("m-3", &request, Some("eureka-state".into())).unwrap();
|
||||
assert_eq!(decode_request(&message).unwrap(), ("m-3".into(), request));
|
||||
|
||||
|
|
@ -14,7 +14,8 @@
|
|||
//! selection (CultNet's, over rows this crate supplies) through the same
|
||||
//! `docs` the rules use; nothing is stored for it.
|
||||
//!
|
||||
//! The wire vocabulary is here too, so the daemon and the client share one set
|
||||
//! The wire vocabulary and its operation envelope (`envelope`) are here too,
|
||||
//! so the daemon and the client share one set
|
||||
//! of types.
|
||||
//!
|
||||
//! Document shape, bounds, formats and keys are `epiphany-pipeline`'s; the
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
|
||||
pub mod admission;
|
||||
mod docs;
|
||||
pub mod envelope;
|
||||
pub mod index;
|
||||
pub mod mind;
|
||||
mod rows;
|
||||
|
|
|
|||
Loading…
Reference in a new issue