use std::{fmt, sync::Arc};
use serde::{Deserialize, Serialize};
use crate::{
completion::{CompletionRequest, CompletionResponse, Message, ModelRef, ProviderCapabilities},
embeddings::EmbeddingResponse,
error::ErrorReport,
id::ConversationId,
operation::RerankRequest,
rerank::RerankResponse,
streaming::Transcript,
tool::ToolResult,
vector_store::request::{Filter, VectorSearchRequest},
wasm_compat::WasmCompatSend,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct EffectId(u64);
impl EffectId {
pub const fn from_raw(raw: u64) -> Self {
Self(raw)
}
pub const fn as_u64(self) -> u64 {
self.0
}
}
impl fmt::Display for EffectId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "effect:{}", self.0)
}
}
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct HandlerKey(Arc<str>);
impl HandlerKey {
pub fn new(key: impl Into<Arc<str>>) -> Self {
Self(key.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn parts(&self) -> KeyParts {
KeyParts::parse(&self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct KeyParts {
pub owner: Option<Arc<str>>,
pub kind: Option<Arc<str>>,
pub label: Arc<str>,
pub generation: Option<u64>,
}
impl KeyParts {
pub fn parse(key: &str) -> Self {
let (owner, rest) = match key.split_once('/') {
Some((owner, rest)) if !owner.is_empty() && !rest.is_empty() => {
(Some(Arc::from(owner)), rest)
}
_ => (None, key),
};
let (rest, generation) = match rest.rsplit_once('#') {
Some((head, digits))
if !digits.is_empty()
&& (digits.len() == 1 || !digits.starts_with('0'))
&& digits.bytes().all(|b| b.is_ascii_digit()) =>
{
match digits.parse::<u64>() {
Ok(generation) => (head, Some(generation)),
Err(_) => (rest, None),
}
}
_ => (rest, None),
};
let (kind, label) = match rest.split_once(':') {
Some((kind, label)) if !kind.is_empty() && !label.is_empty() => {
(Some(Arc::from(kind)), label)
}
_ => (None, rest),
};
Self {
owner,
kind,
label: Arc::from(label),
generation,
}
}
pub fn to_key(&self) -> HandlerKey {
HandlerKey::from(self.to_string())
}
}
impl fmt::Display for KeyParts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(owner) = &self.owner {
write!(f, "{owner}/")?;
}
if let Some(kind) = &self.kind {
write!(f, "{kind}:")?;
}
f.write_str(&self.label)?;
if let Some(generation) = self.generation {
write!(f, "#{generation}")?;
}
Ok(())
}
}
impl fmt::Debug for HandlerKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HandlerKey({:?})", &*self.0)
}
}
impl fmt::Display for HandlerKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl From<&str> for HandlerKey {
fn from(key: &str) -> Self {
Self(Arc::from(key))
}
}
impl From<String> for HandlerKey {
fn from(key: String) -> Self {
Self(Arc::from(key))
}
}
impl AsRef<str> for HandlerKey {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Serialize for HandlerKey {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.0)
}
}
impl<'de> Deserialize<'de> for HandlerKey {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let key = <std::borrow::Cow<'de, str>>::deserialize(deserializer)?;
Ok(Self(Arc::from(&*key)))
}
}
mod arc_str {
use std::sync::Arc;
use serde::{Deserialize, Deserializer, Serializer};
pub(super) fn serialize<S: Serializer>(
value: &Arc<str>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(value)
}
pub(super) fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Arc<str>, D::Error> {
let value = <std::borrow::Cow<'de, str>>::deserialize(deserializer)?;
Ok(Arc::from(&*value))
}
}
mod opt_arc_str {
use std::sync::Arc;
use serde::{Deserialize, Deserializer, Serializer};
pub(super) fn serialize<S: Serializer>(
value: &Option<Arc<str>>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match value {
Some(value) => serializer.serialize_some(&**value),
None => serializer.serialize_none(),
}
}
pub(super) fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<Arc<str>>, D::Error> {
let value = <Option<std::borrow::Cow<'de, str>>>::deserialize(deserializer)?;
Ok(value.map(|value| Arc::from(&*value)))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EffectFamily {
Completion,
Tool,
Embed,
Rerank,
Memory,
Retrieve,
Custom,
}
impl EffectFamily {
pub const fn name(self) -> &'static str {
match self {
Self::Completion => "completion",
Self::Tool => "tool_call",
Self::Embed => "embed",
Self::Rerank => "rerank",
Self::Memory => "memory",
Self::Retrieve => "retrieve",
Self::Custom => "custom",
}
}
}
impl fmt::Display for EffectFamily {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.name())
}
}
pub trait Family: sealed::Sealed + Clone + Copy + Send + Sync + 'static {
const FAMILY: EffectFamily;
type Request: WasmCompatSend + 'static;
type Answer: WasmCompatSend + 'static;
fn wrap(request: Self::Request) -> Result<EffectKind, ErrorReport>;
fn unwrap(outcome: Outcome) -> Result<Self::Answer, ErrorReport>;
fn mismatch(outcome: &Outcome) -> ErrorReport {
ErrorReport::new(
crate::error::ErrorKind::Internal,
format!(
"expected a {} outcome, the handler answered {}",
Self::FAMILY,
outcome.family()
),
)
}
}
mod sealed {
pub trait Sealed {}
}
pub trait Served: sealed::Sealed + 'static {
const SERVED: Option<EffectFamily>;
}
#[diagnostic::do_not_recommend]
impl<F: Family> Served for F {
const SERVED: Option<EffectFamily> = Some(F::FAMILY);
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolCallRequest {
pub name: String,
pub args: String,
}
pub trait CustomEffect: Serialize + serde::de::DeserializeOwned + WasmCompatSend + 'static {
const KIND: &'static str;
type Answer: Serialize + serde::de::DeserializeOwned + WasmCompatSend + 'static;
}
mod key;
pub use key::Key;
pub fn model_key(label: &str) -> HandlerKey {
HandlerKey::from(format!("model:{label}"))
}
pub fn tool_key(name: &str) -> HandlerKey {
HandlerKey::from(format!("tool:{name}"))
}
pub fn embed_key(label: &str) -> HandlerKey {
HandlerKey::from(format!("embed:{label}"))
}
pub fn rerank_key(label: &str) -> HandlerKey {
HandlerKey::from(format!("rerank:{label}"))
}
pub fn memory_key(label: &str) -> HandlerKey {
HandlerKey::from(format!("memory:{label}"))
}
pub fn retrieve_key(label: &str) -> HandlerKey {
HandlerKey::from(format!("retrieve:{label}"))
}
pub mod family {
use std::marker::PhantomData;
use super::{
CustomEffect, EffectFamily, EffectKind, EmbedInputs, EmbedOutputs, Family, MemoryOp,
MemoryOutcome, Outcome, RetrieveQuery, RetrievedDocuments, ToolCallRequest, sealed::Sealed,
};
use crate::{
completion::{CompletionRequest, CompletionResponse},
error::{ErrorKind, ErrorReport},
operation::RerankRequest,
rerank::RerankResponse,
tool::ToolResult,
};
macro_rules! marker {
($($(#[$doc:meta])* $name:ident => $family:ident, $request:ty, $answer:ty, $wrap:expr, $unwrap:expr;)+) => {$(
$(#[$doc])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct $name;
impl Sealed for $name {}
impl Family for $name {
const FAMILY: EffectFamily = EffectFamily::$family;
type Request = $request;
type Answer = $answer;
fn wrap(request: Self::Request) -> Result<EffectKind, ErrorReport> {
let wrap: fn(Self::Request) -> EffectKind = $wrap;
Ok(wrap(request))
}
fn unwrap(outcome: Outcome) -> Result<Self::Answer, ErrorReport> {
let unwrap: fn(Outcome) -> Result<Self::Answer, ErrorReport> = $unwrap;
unwrap(outcome)
}
}
)+};
}
marker! {
Completion => Completion, CompletionRequest, CompletionResponse,
|request| EffectKind::Completion { request, stream: false },
|outcome| match outcome {
Outcome::Completion(response) => Ok(response),
other => Err(Completion::mismatch(&other)),
};
Tool => Tool, ToolCallRequest, ToolResult,
|request| EffectKind::ToolCall { name: request.name, args: request.args },
|outcome| match outcome {
Outcome::ToolResult { result } => Ok(result),
other => Err(Tool::mismatch(&other)),
};
Embed => Embed, EmbedInputs, EmbedOutputs,
|inputs| EffectKind::Embed { inputs },
|outcome| match outcome {
Outcome::Embeddings(outputs) => Ok(outputs),
other => Err(Embed::mismatch(&other)),
};
Rerank => Rerank, RerankRequest, RerankResponse,
|request| EffectKind::Rerank { request },
|outcome| match outcome {
Outcome::Reranked(response) => Ok(response),
other => Err(Rerank::mismatch(&other)),
};
Memory => Memory, MemoryOp, MemoryOutcome,
|op| EffectKind::Memory { op },
|outcome| match outcome {
Outcome::Memory(answer) => Ok(answer),
other => Err(Memory::mismatch(&other)),
};
Retrieve => Retrieve, RetrieveQuery, RetrievedDocuments,
|query| EffectKind::Retrieve { query },
|outcome| match outcome {
Outcome::Documents(documents) => Ok(documents),
other => Err(Retrieve::mismatch(&other)),
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Dynamic;
impl Sealed for Dynamic {}
impl super::Served for Dynamic {
const SERVED: Option<EffectFamily> = None;
}
pub struct Custom<E: CustomEffect>(PhantomData<fn() -> E>);
impl<E: CustomEffect> Custom<E> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<E: CustomEffect> Clone for Custom<E> {
fn clone(&self) -> Self {
*self
}
}
impl<E: CustomEffect> Copy for Custom<E> {}
impl<E: CustomEffect> Default for Custom<E> {
fn default() -> Self {
Self::new()
}
}
impl<E: CustomEffect> std::fmt::Debug for Custom<E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Custom<{}>", E::KIND)
}
}
impl<E: CustomEffect> PartialEq for Custom<E> {
fn eq(&self, _: &Self) -> bool {
true
}
}
impl<E: CustomEffect> Eq for Custom<E> {}
impl<E: CustomEffect> std::hash::Hash for Custom<E> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
E::KIND.hash(state);
}
}
impl<E: CustomEffect> Sealed for Custom<E> {}
impl<E: CustomEffect> Family for Custom<E> {
const FAMILY: EffectFamily = EffectFamily::Custom;
type Request = E;
type Answer = E::Answer;
fn wrap(request: E) -> Result<EffectKind, ErrorReport> {
serde_json::to_value(&request)
.map(|payload| EffectKind::Custom {
kind: std::sync::Arc::from(E::KIND),
payload,
})
.map_err(|error| {
ErrorReport::new(
ErrorKind::Request,
format!("the `{}` effect did not serialize: {error}", E::KIND),
)
})
}
fn unwrap(outcome: Outcome) -> Result<E::Answer, ErrorReport> {
match outcome {
Outcome::Custom { payload: value } => {
serde_json::from_value(value).map_err(|error| {
ErrorReport::new(
ErrorKind::Internal,
format!(
"the answer to the `{}` effect did not deserialize: {error}",
E::KIND
),
)
})
}
other => Err(Self::mismatch(&other)),
}
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HandlerDescriptor {
pub key: HandlerKey,
pub family: FamilyDescriptor,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub layers: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "family", rename_all = "snake_case")]
pub enum FamilyDescriptor {
Completion {
model: ModelRef,
capabilities: ProviderCapabilities,
},
Tool {
name: String,
description: String,
parameters: serde_json::Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
embedding: Option<ToolEmbeddingDescriptor>,
},
Embed {
model: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
dims: Option<usize>,
max_documents: usize,
modality: EmbedModality,
},
Rerank {
model: String,
max_documents: usize,
},
Memory {},
Retrieve {},
Custom {
kind: String,
},
}
impl FamilyDescriptor {
pub const fn family(&self) -> EffectFamily {
match self {
Self::Completion { .. } => EffectFamily::Completion,
Self::Tool { .. } => EffectFamily::Tool,
Self::Embed { .. } => EffectFamily::Embed,
Self::Rerank { .. } => EffectFamily::Rerank,
Self::Memory {} => EffectFamily::Memory,
Self::Retrieve {} => EffectFamily::Retrieve,
Self::Custom { .. } => EffectFamily::Custom,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolEmbeddingDescriptor {
pub context: serde_json::Value,
pub embedding_docs: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EmbedModality {
Text,
Image,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "effect", rename_all = "snake_case")]
pub enum EffectKind {
Completion {
request: CompletionRequest,
stream: bool,
},
ToolCall {
name: String,
args: String,
},
Embed {
inputs: EmbedInputs,
},
Rerank {
request: RerankRequest,
},
Memory {
op: MemoryOp,
},
Retrieve {
query: RetrieveQuery,
},
Custom {
#[serde(with = "arc_str")]
kind: Arc<str>,
payload: serde_json::Value,
},
}
impl EffectKind {
pub const fn family(&self) -> EffectFamily {
match self {
Self::Completion { .. } => EffectFamily::Completion,
Self::ToolCall { .. } => EffectFamily::Tool,
Self::Embed { .. } => EffectFamily::Embed,
Self::Rerank { .. } => EffectFamily::Rerank,
Self::Memory { .. } => EffectFamily::Memory,
Self::Retrieve { .. } => EffectFamily::Retrieve,
Self::Custom { .. } => EffectFamily::Custom,
}
}
pub fn name(&self) -> &str {
match self {
Self::Custom { kind, .. } => kind,
Self::Completion { .. }
| Self::ToolCall { .. }
| Self::Embed { .. }
| Self::Rerank { .. }
| Self::Memory { .. }
| Self::Retrieve { .. } => self.family().name(),
}
}
pub const fn streams(&self) -> bool {
match self {
Self::Completion { stream, .. } => *stream,
Self::ToolCall { .. }
| Self::Embed { .. }
| Self::Rerank { .. }
| Self::Memory { .. }
| Self::Retrieve { .. }
| Self::Custom { .. } => false,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "modality", content = "inputs", rename_all = "snake_case")]
pub enum EmbedInputs {
Texts(Vec<String>),
Images(Vec<Vec<u8>>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "op", rename_all = "snake_case")]
pub enum MemoryOp {
Load {
conversation: ConversationId,
},
Append {
conversation: ConversationId,
messages: Vec<Message>,
},
Clear {
conversation: ConversationId,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "query", rename_all = "snake_case")]
pub enum RetrieveQuery {
TopN {
req: VectorSearchRequest<Filter<serde_json::Value>>,
},
TopNIds {
req: VectorSearchRequest<Filter<serde_json::Value>>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "outcome", rename_all = "snake_case")]
pub enum Outcome {
Completion(CompletionResponse),
ToolResult {
result: ToolResult,
},
Embeddings(EmbedOutputs),
Reranked(RerankResponse),
Memory(MemoryOutcome),
Documents(RetrievedDocuments),
Custom {
payload: serde_json::Value,
},
}
impl Outcome {
pub const fn family(&self) -> EffectFamily {
match self {
Self::Completion(_) => EffectFamily::Completion,
Self::ToolResult { .. } => EffectFamily::Tool,
Self::Embeddings(_) => EffectFamily::Embed,
Self::Reranked(_) => EffectFamily::Rerank,
Self::Memory(_) => EffectFamily::Memory,
Self::Documents(_) => EffectFamily::Retrieve,
Self::Custom { .. } => EffectFamily::Custom,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "modality", content = "response", rename_all = "snake_case")]
pub enum EmbedOutputs {
Texts(EmbeddingResponse),
Images(EmbeddingResponse),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "memory", rename_all = "snake_case")]
pub enum MemoryOutcome {
Loaded {
messages: Vec<Message>,
},
Appended,
Cleared,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "retrieved", content = "results", rename_all = "snake_case")]
pub enum RetrievedDocuments {
Scored(Vec<(f64, String, serde_json::Value)>),
Ids(Vec<(f64, String)>),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Delivery {
pub batch: u64,
pub id: EffectId,
pub kind: DeliveryKind,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "delivery", rename_all = "snake_case")]
pub enum DeliveryKind {
Outcome,
Cancelled,
Stream {
items: usize,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EffectRecord {
#[serde(deserialize_with = "Option::deserialize")]
pub tool_output: Option<crate::tool::ToolResultContext>,
pub id: EffectId,
pub key: HandlerKey,
pub kind: EffectKind,
pub outcome: Result<Outcome, ErrorReport>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub events: Option<Transcript>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stream_origin: Option<crate::message::Origin>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent: Option<EffectId>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "opt_arc_str")]
pub scope: Option<std::sync::Arc<str>>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct EffectRow(std::collections::BTreeMap<HandlerKey, EffectFamily>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RowGap {
pub key: HandlerKey,
pub needed: EffectFamily,
pub served: Option<EffectFamily>,
}
impl std::fmt::Display for RowGap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.served {
Some(served) => write!(
f,
"`{}` is needed as {} but served as {served}",
self.key, self.needed
),
None => write!(f, "`{}` ({}) is not served", self.key, self.needed),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RowDiff {
Missing {
key: HandlerKey,
family: EffectFamily,
},
Extra {
key: HandlerKey,
family: EffectFamily,
},
Family {
key: HandlerKey,
this: EffectFamily,
other: EffectFamily,
},
}
impl std::fmt::Display for RowDiff {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Missing { key, family } => write!(f, "`{key}` ({family}) is missing"),
Self::Extra { key, family } => write!(f, "`{key}` ({family}) is extra"),
Self::Family { key, this, other } => {
write!(f, "`{key}` is {this} here and {other} there")
}
}
}
}
impl EffectRow {
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, key: HandlerKey, family: EffectFamily) -> Option<EffectFamily> {
self.0.insert(key, family)
}
pub fn insert_if_absent(&mut self, key: HandlerKey, family: EffectFamily) {
self.0.entry(key).or_insert(family);
}
pub fn remove(&mut self, key: &HandlerKey) -> Option<EffectFamily> {
self.0.remove(key)
}
pub fn get(&self, key: &HandlerKey) -> Option<&EffectFamily> {
self.0.get(key)
}
pub fn contains_key(&self, key: &HandlerKey) -> bool {
self.0.contains_key(key)
}
pub fn keys(&self) -> impl Iterator<Item = &HandlerKey> {
self.0.keys()
}
pub fn iter(&self) -> impl Iterator<Item = (&HandlerKey, &EffectFamily)> {
self.0.iter()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn is_subset_of(&self, handlers: &[HandlerDescriptor]) -> Result<(), RowGap> {
for (key, needed) in &self.0 {
let served = handlers
.iter()
.find(|descriptor| &descriptor.key == key)
.map(|descriptor| descriptor.family.family());
match served {
Some(served) if served == *needed => {}
served => {
return Err(RowGap {
key: key.clone(),
needed: *needed,
served,
});
}
}
}
Ok(())
}
pub fn diff(&self, other: &EffectRow) -> Vec<RowDiff> {
let mut diffs = Vec::new();
for (key, family) in &self.0 {
match other.0.get(key) {
None => diffs.push(RowDiff::Missing {
key: key.clone(),
family: *family,
}),
Some(theirs) if theirs != family => diffs.push(RowDiff::Family {
key: key.clone(),
this: *family,
other: *theirs,
}),
Some(_) => {}
}
}
for (key, family) in &other.0 {
if !self.0.contains_key(key) {
diffs.push(RowDiff::Extra {
key: key.clone(),
family: *family,
});
}
}
diffs
}
}
impl FromIterator<(HandlerKey, EffectFamily)> for EffectRow {
fn from_iter<I: IntoIterator<Item = (HandlerKey, EffectFamily)>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl<'a> IntoIterator for &'a EffectRow {
type Item = (&'a HandlerKey, &'a EffectFamily);
type IntoIter = std::collections::btree_map::Iter<'a, HandlerKey, EffectFamily>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl IntoIterator for EffectRow {
type Item = (HandlerKey, EffectFamily);
type IntoIter = std::collections::btree_map::IntoIter<HandlerKey, EffectFamily>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
const _: fn() = || {
fn assert_wire<T: Clone + Send + Sync + 'static + Serialize + serde::de::DeserializeOwned>() {}
assert_wire::<EffectId>();
assert_wire::<HandlerKey>();
assert_wire::<EffectFamily>();
assert_wire::<HandlerDescriptor>();
assert_wire::<FamilyDescriptor>();
assert_wire::<ToolEmbeddingDescriptor>();
assert_wire::<EmbedModality>();
assert_wire::<EffectKind>();
assert_wire::<EmbedInputs>();
assert_wire::<RerankRequest>();
assert_wire::<MemoryOp>();
assert_wire::<RetrieveQuery>();
assert_wire::<Outcome>();
assert_wire::<EmbedOutputs>();
assert_wire::<MemoryOutcome>();
assert_wire::<RetrievedDocuments>();
assert_wire::<EffectRecord>();
assert_wire::<EffectRow>();
assert_wire::<Transcript>();
};
#[cfg(test)]
mod tests;