use async_trait::async_trait;
use serde_json::Value as JsonValue;
use langgraph_checkpoint::config::RunnableConfig;
use crate::runnable::{Runnable, RunnableError};
const PASSTHROUGH: &str = "__passthrough__";
#[derive(Debug, Clone)]
pub struct ChannelWriteEntry {
pub channel: String,
pub value: Option<JsonValue>,
pub skip_none: bool,
}
impl ChannelWriteEntry {
pub fn new(channel: impl Into<String>, value: Option<JsonValue>) -> Self {
Self {
channel: channel.into(),
value,
skip_none: false,
}
}
pub fn passthrough(channel: impl Into<String>) -> Self {
Self {
channel: channel.into(),
value: None,
skip_none: false,
}
}
}
pub struct ChannelWrite {
entries: Vec<ChannelWriteEntry>,
}
impl ChannelWrite {
pub fn new(entries: Vec<ChannelWriteEntry>) -> Self {
Self { entries }
}
fn assemble_writes(&self, input: &JsonValue) -> Vec<(String, JsonValue)> {
let mut writes = Vec::new();
for entry in &self.entries {
let value = match &entry.value {
Some(v) => v.clone(),
None => input.clone(), };
if entry.skip_none && value.is_null() {
continue;
}
writes.push((entry.channel.clone(), value));
}
writes
}
}
#[async_trait]
impl Runnable for ChannelWrite {
fn invoke(&self, input: &JsonValue, config: &RunnableConfig) -> Result<JsonValue, RunnableError> {
let _writes = self.assemble_writes(input);
if let Some(configurable) = config.get("configurable") {
if let Some(_send_fn) = configurable.get(crate::constants::CONFIG_KEY_SEND) {
}
}
Ok(input.clone())
}
async fn ainvoke(&self, input: &JsonValue, config: &RunnableConfig) -> Result<JsonValue, RunnableError> {
self.invoke(input, config)
}
fn name(&self) -> &str {
"ChannelWrite"
}
}
pub fn write_to_targets(targets: &[String]) -> ChannelWrite {
let entries: Vec<ChannelWriteEntry> = targets
.iter()
.map(|t| {
ChannelWriteEntry::new(
format!("branch:to:{}", t),
Some(JsonValue::String(t.clone())),
)
})
.collect();
ChannelWrite::new(entries)
}