| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| use crate::StoreError; | |
| use maka_agent_facts::attachment::AttachmentRef; | |
| use maka_agent_facts::attachment::StorageRef; | |
| use maka_agent_facts::event::Fact; | |
| use maka_agent_facts::event::InvocationInput; | |
| use maka_agent_facts::event::RuntimeEvent; | |
| use maka_agent_facts::event::ToolOutcome; | |
| use maka_agent_facts::tool_output::DurableToolProjection; | |
| /// Only typed canonical references convey ownership; arbitrary plugin JSON does not. | |
| pub(crate) fn from_event(event: &RuntimeEvent) -> Vec<(&StorageRef, Option<&AttachmentRef>)> { | |
| let mut references: Vec<(&StorageRef, Option<&AttachmentRef>)> = Vec::new(); | |
| match &event.fact { | |
| Fact::InvocationOpened { | |
| input: | |
| InvocationInput::Message { | |
| content, | |
| source_messages, | |
| .. | |
| }, | |
| .. | |
| } => { | |
| references.extend( | |
| content | |
| .attachments | |
| .iter() | |
| .flatten() | |
| .map(|a| (&a.storage_ref, Some(a))), | |
| ); | |
| for message in source_messages { | |
| references.extend( | |
| message | |
| .unprepared_content | |
| .attachments | |
| .iter() | |
| .flatten() | |
| .map(|a| (&a.storage_ref, Some(a))), | |
| ); | |
| references.extend( | |
| message | |
| .message | |
| .content | |
| .attachments | |
| .iter() | |
| .flatten() | |
| .map(|a| (&a.storage_ref, Some(a))), | |
| ); | |
| } | |
| } | |
| Fact::MessageSteered { message, source } => { | |
| references.extend( | |
| message | |
| .content | |
| .attachments | |
| .iter() | |
| .flatten() | |
| .map(|a| (&a.storage_ref, Some(a))), | |
| ); | |
| if let Some(source) = source { | |
| references.extend( | |
| source | |
| .unprepared_content | |
| .attachments | |
| .iter() | |
| .flatten() | |
| .map(|a| (&a.storage_ref, Some(a))), | |
| ); | |
| } | |
| } | |
| Fact::ToolSettled { | |
| outcome: | |
| ToolOutcome::Succeeded { | |
| model_projection: DurableToolProjection::Content { parts }, | |
| .. | |
| }, | |
| .. | |
| } => { | |
| references.extend( | |
| parts | |
| .iter() | |
| .filter_map(|part| part.media().map(|(reference, _)| (reference, None))), | |
| ); | |
| } | |
| _ => {} | |
| } | |
| references | |
| } | |
| /// Only original editable inputs belong to Revision evidence. | |
| pub(crate) fn revision(event: &RuntimeEvent) -> Result<Vec<&AttachmentRef>, StoreError> { | |
| if !matches!( | |
| &event.fact, | |
| Fact::InvocationOpened { | |
| input: InvocationInput::Message { .. }, | |
| .. | |
| } | Fact::MessageSteered { | |
| source: Some(_), | |
| .. | |
| } | |
| ) { | |
| return Err(StoreError::InvalidTransition( | |
| "revision source has no canonical input".into(), | |
| )); | |
| } | |
| Ok(crate::message_sources::roots(event) | |
| .iter() | |
| .flat_map(|message| message.unprepared_content.attachments.iter().flatten()) | |
| .collect()) | |
| } |