pub mod checkpoint;
pub mod content;
pub mod reflect;
use bevy_ecs::prelude::*;
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
use rig_core::{
completion::{
Usage as WireUsage,
message::{
AssistantContent, AssistantMessage, CallId, Message, ToolChoice, ToolName, UserContent,
},
},
error::ErrorReport,
tool::ToolContext,
};
use serde::{Deserialize, Serialize};
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Owner(pub String);
#[derive(Component, Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Preamble(pub Option<String>);
#[derive(Component, Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Temperature(pub Option<f64>);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct MaxTokens(pub Option<u64>);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct AcceptUnknownFinishReasons(pub bool);
#[derive(Component, Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct AdditionalParams(
#[reflect(remote = crate::agent::reflect::OptionalJsonReflect)] pub Option<serde_json::Value>,
);
#[derive(Component, Debug, Clone, Default, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(opaque, Component, Debug, PartialEq, Serialize, Deserialize)]
pub struct Options(pub rig_core::completion::GenerationOptions);
#[derive(Component, Debug, Clone, Default, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(opaque, Component, Debug, PartialEq, Serialize, Deserialize)]
pub struct ProviderOptions(pub rig_core::completion::ProviderOptions);
impl ProviderOptions {
pub fn set<O: rig_core::completion::ExtensionOptions>(self, options: O) -> Self {
Self(self.0.set(options))
}
}
#[derive(Component, Debug, Clone, Default, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct ToolChoiceSpec(
#[reflect(remote = crate::agent::reflect::ToolChoiceReflect)] pub Option<ToolChoice>,
);
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[serde(rename_all = "snake_case")]
pub enum OutputKind {
#[default]
Auto,
Native,
Tool,
Prompted,
}
#[derive(Component, Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Output {
pub mode: OutputKind,
#[reflect(remote = crate::agent::reflect::OptionalJsonReflect)]
pub schema: Option<serde_json::Value>,
}
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct OutputToolConfig {
pub name: Option<String>,
pub description: Option<String>,
pub augment_preamble: bool,
}
impl Default for OutputToolConfig {
fn default() -> Self {
Self {
name: None,
description: None,
augment_preamble: true,
}
}
}
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct MaxTurns(pub usize);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct ProviderRetries(pub usize);
pub const DEFAULT_PROVIDER_RETRIES: usize = 3;
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Backoff {
pub base: std::time::Duration,
pub max: std::time::Duration,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[serde(rename_all = "snake_case")]
pub enum Unhandled {
#[default]
Fail,
Ignore,
}
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct InvalidCalls {
pub retries: usize,
pub unhandled: Unhandled,
}
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct PolicyVersion(pub String);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct ToolPolicy {
pub concurrency: usize,
}
impl Default for ToolPolicy {
fn default() -> Self {
Self { concurrency: 1 }
}
}
#[derive(Component, Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct ToolContextSpec(
#[reflect(remote = crate::agent::reflect::ToolContextReflect)] pub ToolContext,
);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct DefaultMaxTurns(pub Option<usize>);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = ModelOf)]
#[reflect(Component)]
pub struct UsesModel(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = UsesModel)]
#[reflect(Component)]
pub struct ModelOf(Vec<Entity>);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = RememberedBy)]
#[reflect(Component)]
pub struct Remembers(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = Remembers)]
#[reflect(Component)]
pub struct RememberedBy(Vec<Entity>);
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Conversation(pub String);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Remembered;
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Remembering;
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct MemoryAppendScheduled;
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = RetrievedBy)]
#[reflect(Component)]
pub struct Retrieves(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = Retrieves)]
#[reflect(Component)]
pub struct RetrievedBy(Vec<Entity>);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Retrieval {
pub samples: u64,
pub what: RetrievalKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[serde(rename_all = "snake_case")]
pub enum RetrievalKind {
Documents,
Tools,
}
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Retrievable;
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Retrieving;
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = RoutedTo)]
#[reflect(Component)]
pub struct Route(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = Route)]
#[reflect(Component)]
pub struct RoutedTo(Vec<Entity>);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = Grants)]
#[reflect(Component)]
pub struct Grant(pub Entity);
#[derive(Component, Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(opaque, Component, Debug, PartialEq, Serialize, Deserialize)]
pub struct ToolAccess {
pub executable: Option<std::collections::BTreeMap<String, rig_core::effect::HandlerKey>>,
pub allowed: Option<std::collections::BTreeSet<String>>,
}
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = Grant)]
#[reflect(Component)]
pub struct Grants(Vec<Entity>);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = ContextOf)]
#[reflect(Component)]
pub struct Context(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = Context)]
#[reflect(Component)]
pub struct ContextOf(Vec<Entity>);
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct DocumentId(pub String);
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct DocumentText(pub String);
#[derive(Component, Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct DocumentProps(pub std::collections::HashMap<String, String>);
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = AttachedTo)]
#[reflect(Component)]
pub struct Attachment(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = Attachment)]
#[reflect(Component)]
pub struct AttachedTo(Vec<Entity>);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Utterance;
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[serde(rename_all = "snake_case")]
#[reflect(Component)]
pub enum Role {
User,
Assistant,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
#[serde(tag = "role", rename_all = "snake_case")]
#[reflect(opaque, Debug, PartialEq, Serialize, Deserialize)]
pub enum MessageParts {
User {
content: Vec<UserContent>,
},
Assistant(AssistantMessage),
}
impl MessageParts {
pub fn user(content: Vec<UserContent>) -> Result<Self, content::parts::ContentError> {
if content.is_empty() {
return Err(content::parts::ContentError::Shape);
}
Ok(Self::User { content })
}
pub fn assistant(message: AssistantMessage) -> Result<Self, content::parts::ContentError> {
if message.content.is_empty() {
return Err(content::parts::ContentError::Shape);
}
Ok(Self::Assistant(message))
}
pub fn to_message(&self) -> Message {
match self {
Self::User { content } => Message::User {
content: content.clone(),
},
Self::Assistant(message) => Message::Assistant(message.clone()),
}
}
pub fn from_message(message: &Message) -> Option<Self> {
match message {
Message::System { .. } => None,
Message::User { content } => Some(Self::User {
content: content.clone(),
}),
Message::Assistant(message) => Some(Self::Assistant(message.clone())),
}
}
pub fn role(&self) -> Role {
match self {
Self::User { .. } => Role::User,
Self::Assistant { .. } => Role::Assistant,
}
}
}
#[derive(Component, Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component, opaque, Debug, PartialEq, Serialize, Deserialize)]
pub struct Prompt(pub Vec<UserContent>);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Ready;
impl From<&str> for Prompt {
fn from(text: &str) -> Self {
Self(vec![UserContent::text(text)])
}
}
impl From<String> for Prompt {
fn from(text: String) -> Self {
Self(vec![UserContent::text(text)])
}
}
impl From<UserContent> for Prompt {
fn from(part: UserContent) -> Self {
Self(vec![part])
}
}
impl From<Vec<UserContent>> for Prompt {
fn from(parts: Vec<UserContent>) -> Self {
Self(parts)
}
}
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[require(
Cursor,
OutputRetries,
InvalidRetries,
ProviderRetried,
OutputToolName,
Usage,
StreamRequested
)]
#[component(on_add = stamp_run)]
#[reflect(Component)]
pub struct Run;
fn stamp_run(
mut world: bevy_ecs::world::DeferredWorld<'_>,
context: bevy_ecs::lifecycle::HookContext,
) {
let entity = context.entity;
if world.get::<RunSeq>(entity).is_none()
&& let Some(mut counter) = world.get_resource_mut::<RunCounter>()
{
let seq = counter.0;
counter.0 += 1;
let owner = world
.get::<RunOf>(entity)
.and_then(|run_of| world.get::<Owner>(run_of.0))
.map(|owner| owner.0.clone())
.unwrap_or_default();
world
.commands()
.entity(entity)
.insert((RunSeq(seq), crate::bus::Scope(format!("{owner}/run#{seq}"))));
}
}
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = Runs)]
#[reflect(Component)]
pub struct RunOf(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = RunOf)]
#[reflect(Component)]
pub struct Runs(Vec<Entity>);
impl Runs {
pub fn runs(&self) -> &[Entity] {
&self.0
}
}
#[derive(
Component,
Debug,
Clone,
Copy,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Reflect,
)]
#[reflect(Component)]
pub struct RunSeq(pub u64);
#[derive(Resource, Debug, Default, Reflect)]
#[reflect(Resource)]
pub struct RunCounter(pub(crate) u64);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct StreamRequested(pub bool);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Cursor {
pub turn: usize,
}
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[component(immutable)]
#[serde(rename_all = "snake_case")]
#[reflect(Component)]
pub enum RunPhase {
LoadingMemory,
Assembling,
AwaitingModel,
ResolvingTools,
}
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Batch {
pub calls: usize,
}
#[derive(Component, Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct ToolCallSlot {
pub index: usize,
#[reflect(remote = crate::agent::reflect::ToolCallIdReflect)]
pub id: CallId,
#[reflect(remote = crate::agent::reflect::ToolNameReflect)]
pub name: ToolName,
}
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Settled;
#[derive(Component, Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Failed(pub Failure);
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
#[serde(tag = "failure", rename_all = "snake_case")]
#[reflect(opaque, Debug, PartialEq, Serialize, Deserialize)]
pub enum Failure {
Content(content::parts::ContentError),
MaxTurns {
limit: usize,
},
UnknownToolCall {
name: String,
},
Provider(ErrorReport),
Cancelled(ErrorReport),
Unsupported(String),
OutputToolCollision {
name: String,
},
Tool(ErrorReport),
Memory(ErrorReport),
}
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct RunResult(pub String);
#[derive(Component, Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Usage(#[reflect(remote = crate::agent::reflect::UsageReflect)] pub WireUsage);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct OutputRetries(pub usize);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct InvalidRetries(pub usize);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct ProviderRetried(pub usize);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct ProviderRetrying;
#[derive(Component, Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct OutputToolName(pub Option<String>);
#[derive(
Component, Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Reflect,
)]
#[reflect(Component)]
pub struct Turn;
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
#[relationship(relationship_target = AdvertisedOn)]
#[reflect(Component)]
pub struct Advert(pub Entity);
#[derive(Component, Debug, Default, Reflect)]
#[relationship_target(relationship = Advert)]
#[reflect(Component)]
pub struct AdvertisedOn(Vec<Entity>);
#[derive(Component, Debug, Clone, Default, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Outputs {
#[reflect(remote = crate::agent::reflect::AssistantContentsReflect)]
pub content: Vec<AssistantContent>,
pub head: content::parts::AssistantHead,
pub done: bool,
pub usage_recorded: bool,
pub stream_validated: usize,
}
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Cancelled(pub String);
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Retry {
pub feedback: Option<String>,
}
#[derive(Component, Debug, Clone, Default, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(opaque, Component, Debug, PartialEq, Serialize, Deserialize)]
pub struct RequestPatch {
pub preamble: Option<String>,
pub temperature: Option<f64>,
pub max_tokens: Option<u64>,
pub tool_choice: Option<ToolChoice>,
pub active_tools: Option<Vec<String>>,
pub additional_params: Option<serde_json::Value>,
pub extra_context: Vec<rig_core::completion::Document>,
pub history: Option<Vec<MessageParts>>,
}
impl RequestPatch {
#[must_use = "the merged patch is the returned value"]
pub fn merge(mut self, later: Self) -> Self {
self.extra_context.extend(later.extra_context);
self.additional_params = match (self.additional_params.take(), later.additional_params) {
(Some(base), Some(patch)) if base.is_object() && patch.is_object() => {
Some(rig_core::json_utils::merge(base, patch))
}
(base, patch) => patch.or(base),
};
self.preamble = later.preamble.or(self.preamble);
self.temperature = later.temperature.or(self.temperature);
self.max_tokens = later.max_tokens.or(self.max_tokens);
self.tool_choice = later.tool_choice.or(self.tool_choice);
self.history = later.history.or(self.history);
self.active_tools = match (self.active_tools.take(), later.active_tools) {
(Some(earlier), Some(later)) => Some(
earlier
.into_iter()
.filter(|name| later.contains(name))
.collect(),
),
(earlier, later) => earlier.or(later),
};
self
}
}
#[derive(Component, Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct Reprompt(#[reflect(remote = crate::agent::reflect::MessageReflect)] pub Message);
#[derive(Component, Debug, Clone, PartialEq, Serialize, Deserialize, Reflect)]
#[reflect(Component)]
pub struct InvalidCall {
#[reflect(remote = crate::agent::reflect::ToolCallIdReflect)]
pub id: CallId,
pub name: String,
#[reflect(remote = crate::agent::reflect::JsonReflect)]
pub arguments: serde_json::Value,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
#[reflect(remote = crate::agent::reflect::AssistantContentsReflect)]
pub prefix: Vec<AssistantContent>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stream_offset: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[reflect(remote = crate::agent::content::reflect::OriginReflect)]
pub origin: Option<rig_core::message::Origin>,
}
#[derive(Component, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Reflect)]
#[serde(tag = "resolution", rename_all = "snake_case")]
#[reflect(Component)]
pub enum Resolution {
Fail,
Ignore,
Retry {
feedback: String,
},
Repair {
to: String,
},
Skip {
reason: String,
},
}
const _: () = {
const fn assert_serde<T: Serialize + serde::de::DeserializeOwned>() {}
assert_serde::<Owner>();
assert_serde::<Preamble>();
assert_serde::<Output>();
assert_serde::<Failed>();
assert_serde::<Outputs>();
assert_serde::<InvalidCall>();
assert_serde::<Resolution>();
assert_serde::<ToolPolicy>();
assert_serde::<ToolContextSpec>();
assert_serde::<Batch>();
assert_serde::<ToolCallSlot>();
assert_serde::<Cancelled>();
assert_serde::<Retry>();
assert_serde::<RequestPatch>();
assert_serde::<Conversation>();
assert_serde::<Retrieval>();
};
pub fn fork(world: &mut World, run: Entity) -> Entity {
let seq = {
let mut counter = world.resource_mut::<RunCounter>();
let seq = counter.0;
counter.0 += 1;
seq
};
let owner = world
.get::<RunOf>(run)
.and_then(|run_of| world.get::<Owner>(run_of.0))
.map(|owner| owner.0.clone())
.unwrap_or_default();
use bevy_ecs::entity::{EntityCloner, EntityHashMap};
use checkpoint::{AssistantForTurns, ResultsForTurns, TurnAssistant, TurnResults};
let links: Vec<_> = world
.query::<(
Entity,
&ChildOf,
Option<&TurnAssistant>,
Option<&TurnResults>,
)>()
.iter(world)
.filter(|(_, parent, _, _)| parent.parent() == run)
.map(|(turn, _, assistant, results)| (turn, assistant.copied(), results.copied()))
.collect();
let clone = world.spawn_empty().id();
let mut mapped = EntityHashMap::default();
mapped.insert(run, clone);
let mut cloner = EntityCloner::build_opt_out(world);
cloner.linked_cloning(true).deny::<(
crate::bus::PendingEffect,
crate::bus::Seq,
crate::bus::Issued,
crate::bus::Reserved,
crate::bus::EffectOutcome,
crate::bus::ToolInputs,
crate::bus::ToolOutputs,
ToolCallSlot,
TurnAssistant,
AssistantForTurns,
TurnResults,
ResultsForTurns,
)>();
cloner.finish().clone_entity_mapped(world, run, &mut mapped);
world.flush();
for (turn, assistant, results) in links {
if let Some(turn) = mapped.get(&turn).copied() {
if let Some(TurnAssistant(target)) = assistant {
let target = mapped.get(&target).copied().unwrap_or(target);
world.entity_mut(turn).insert(TurnAssistant(target));
}
if let Some(TurnResults(target)) = results {
let target = mapped.get(&target).copied().unwrap_or(target);
world.entity_mut(turn).insert(TurnResults(target));
}
}
}
world
.entity_mut(clone)
.insert((RunSeq(seq), crate::bus::Scope(format!("{owner}/run#{seq}"))));
clone
}
#[cfg(test)]
mod tests;