From f9800ec98253f5015775ff088b5486ce4ea3c4d7 Mon Sep 17 00:00:00 2001 From: bsorrentino Date: Tue, 6 Aug 2024 13:03:02 +0200 Subject: [PATCH 1/7] feat: start implementing checkpoint - add BaseCheckpointSaver - add Checkpoint - add CheckpointConfig - add CompileConfig - add InvokeConfig work on #11 --- .../org/bsc/langgraph4j/CompileConfig.java | 45 +++++++++++++++++++ .../org/bsc/langgraph4j/CompiledGraph.java | 33 ++++++++++++-- .../java/org/bsc/langgraph4j/EdgeValue.java | 2 +- .../org/bsc/langgraph4j/InvokeConfig.java | 39 ++++++++++++++++ .../java/org/bsc/langgraph4j/StateGraph.java | 16 ++++++- .../state/BaseCheckpointSaver.java | 11 +++++ .../org/bsc/langgraph4j/state/Checkpoint.java | 35 +++++++++++++++ .../langgraph4j/state/CheckpointConfig.java | 8 ++++ 8 files changed, 182 insertions(+), 7 deletions(-) create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/state/BaseCheckpointSaver.java create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/state/Checkpoint.java create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/state/CheckpointConfig.java diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java new file mode 100644 index 0000000..2ca5415 --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java @@ -0,0 +1,45 @@ +package org.bsc.langgraph4j; + +import org.bsc.langgraph4j.state.BaseCheckpointSaver; + +import java.util.Optional; + + +public class CompileConfig { + + private BaseCheckpointSaver checkpointSaver; + private String[] interruptBefore = {}; + private String[] interruptAfter = {}; + + public Optional getCheckpointSaver() { return Optional.ofNullable(checkpointSaver); } + public String[] getInterruptBefore() { return interruptBefore; } + public String[] getInterruptAfter() { return interruptAfter; } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private final CompileConfig config = new CompileConfig(); + + public Builder checkpointSaver(BaseCheckpointSaver checkpointSaver) { + this.config.checkpointSaver = checkpointSaver; + return this; + } + public Builder interruptBefore(String... interruptBefore) { + this.config.interruptBefore = interruptBefore; + return this; + } + public Builder interruptAfter(String... interruptAfter) { + this.config.interruptAfter = interruptAfter; + return this; + } + public CompileConfig build() { + return config; + } + } + + + private CompileConfig() {} + +} diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java index 6336fca..e205b89 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java @@ -31,14 +31,16 @@ public class CompiledGraph { final Map> edges = new LinkedHashMap<>(); private int maxIterations = 25; + private final CompileConfig compileConfig; /** * Constructs a CompiledGraph with the given StateGraph. * * @param stateGraph the StateGraph to be used in this CompiledGraph */ - protected CompiledGraph(StateGraph stateGraph) { + protected CompiledGraph(StateGraph stateGraph, CompileConfig compileConfig ) { this.stateGraph = stateGraph; + this.compileConfig = compileConfig; stateGraph.nodes.forEach(n -> nodes.put(n.id(), n.action()) ); @@ -109,10 +111,11 @@ private String getEntryPoint( State state ) throws Exception { * Creates an AsyncGenerator stream of NodeOutput based on the provided inputs. * * @param inputs the input map + * @param config the invoke configuration * @return an AsyncGenerator stream of NodeOutput * @throws Exception if there is an error creating the stream */ - public AsyncGenerator> stream(Map inputs ) throws Exception { + public AsyncGenerator> stream(Map inputs, InvokeConfig config ) throws Exception { return AsyncGeneratorQueue.of(new LinkedBlockingQueue<>(), queue -> { @@ -171,16 +174,27 @@ public AsyncGenerator> stream(Map inputs ) thro } + /** + * Creates an AsyncGenerator stream of NodeOutput based on the provided inputs. + * + * @param inputs the input map + * @return an AsyncGenerator stream of NodeOutput + * @throws Exception if there is an error creating the stream + */ + public AsyncGenerator> stream(Map inputs ) throws Exception { + return this.stream( inputs, InvokeConfig.builder().build() ); + } /** * Invokes the graph execution with the provided inputs and returns the final state. * * @param inputs the input map + * @param config the invoke configuration * @return an Optional containing the final state if present, otherwise an empty Optional * @throws Exception if there is an error during invocation */ - public Optional invoke(Map inputs ) throws Exception { + public Optional invoke(Map inputs, InvokeConfig config ) throws Exception { - var sourceIterator = stream(inputs).iterator(); + var sourceIterator = stream(inputs, config).iterator(); var result = StreamSupport.stream( Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED), @@ -189,6 +203,17 @@ public Optional invoke(Map inputs ) throws Exception { return result.reduce((a, b) -> b).map( NodeOutput::state); } + /** + * Invokes the graph execution with the provided inputs and returns the final state. + * + * @param inputs the input map + * @return an Optional containing the final state if present, otherwise an empty Optional + * @throws Exception if there is an error during invocation + */ + public Optional invoke(Map inputs ) throws Exception { + return this.invoke( inputs, InvokeConfig.builder().build() ); + } + /** * Generates a drawable graph representation of the state graph. * diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/EdgeValue.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/EdgeValue.java index 2677ba2..21ef364 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/EdgeValue.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/EdgeValue.java @@ -7,7 +7,7 @@ @Value @Accessors(fluent = true) -class EdgeValue { +public class EdgeValue { /** * The unique identifier for the edge value. diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java new file mode 100644 index 0000000..1588a35 --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java @@ -0,0 +1,39 @@ +package org.bsc.langgraph4j; + +import org.bsc.langgraph4j.state.CheckpointConfig; + +import java.util.Optional; + +public class InvokeConfig { + + private CheckpointConfig checkpointConfig; + + public Optional getCheckpointConfig() { + return Optional.ofNullable(checkpointConfig); + } + + static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String checkpointThreadId; + + public Builder checkpointThreadId(String threadId) { + this.checkpointThreadId = threadId; + return this; + } + public InvokeConfig build() { + InvokeConfig result = new InvokeConfig(); + + if( checkpointThreadId != null ) { + result.checkpointConfig = CheckpointConfig.of(checkpointThreadId); + } + + return result; + } + } + + private InvokeConfig() {} +} diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java index 362528b..30ffa4d 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java @@ -198,10 +198,11 @@ private Node makeFakeNode(String id) { /** * Compiles the state graph into a compiled graph. * + * @param config the compile configuration * @return a compiled graph * @throws GraphStateException if there are errors related to the graph state */ - public CompiledGraph compile() throws GraphStateException { + public CompiledGraph compile( CompileConfig config ) throws GraphStateException { if (entryPoint == null) { throw Errors.missingEntryPoint.exception(); } @@ -237,6 +238,17 @@ public CompiledGraph compile() throws GraphStateException { } } - return new CompiledGraph<>(this); + return new CompiledGraph<>(this, config); } + + /** + * Compiles the state graph into a compiled graph. + * + * @return a compiled graph + * @throws GraphStateException if there are errors related to the graph state + */ + public CompiledGraph compile() throws GraphStateException { + return compile(CompileConfig.builder().build()); + } + } diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/BaseCheckpointSaver.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/BaseCheckpointSaver.java new file mode 100644 index 0000000..1877c76 --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/BaseCheckpointSaver.java @@ -0,0 +1,11 @@ +package org.bsc.langgraph4j.state; + +import java.util.Collection; +import java.util.Optional; + +public interface BaseCheckpointSaver { + + Collection list(); + Optional get( String id ); + void put( Checkpoint checkpoint ); +} diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/Checkpoint.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/Checkpoint.java new file mode 100644 index 0000000..dad10fb --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/Checkpoint.java @@ -0,0 +1,35 @@ +package org.bsc.langgraph4j.state; + +import lombok.Value; + +import java.util.*; + +public class Checkpoint { + + @lombok.Value(staticConstructor="of") + public static class Value { + AgentState state; + String next; + } + + private final String id; + private final Value value; + + public final String getId() { + return id; + } + public final Value getValue() { + return value; + } + + public Checkpoint( Value value ) { + this(UUID.randomUUID().toString(), value ); + } + public Checkpoint(String id, Value value) { + Objects.requireNonNull(id, "id cannot be null"); + Objects.requireNonNull(value, "value cannot be null"); + this.id = id; + this.value = value; + } + +} diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/CheckpointConfig.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/CheckpointConfig.java new file mode 100644 index 0000000..0b33249 --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/CheckpointConfig.java @@ -0,0 +1,8 @@ +package org.bsc.langgraph4j.state; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class CheckpointConfig { + String threadId; +} From b8ab321093899c6e7293430d79bfc5ab94012736 Mon Sep 17 00:00:00 2001 From: bsorrentino Date: Tue, 6 Aug 2024 18:50:36 +0200 Subject: [PATCH 2/7] build: upgrade async-generator dependency, add slf4j to test scope work on #11 --- core-jdk8/pom.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core-jdk8/pom.xml b/core-jdk8/pom.xml index ab237d2..a543f47 100644 --- a/core-jdk8/pom.xml +++ b/core-jdk8/pom.xml @@ -27,7 +27,7 @@ org.bsc.async async-generator-jdk8 - 2.0.0 + 2.0.1 @@ -41,6 +41,12 @@ test + + org.slf4j + slf4j-jdk14 + test + + From 1564efca643c31c48df649d7729b646b3648f40f Mon Sep 17 00:00:00 2001 From: bsorrentino Date: Tue, 6 Aug 2024 18:52:17 +0200 Subject: [PATCH 3/7] feat: finalize checkpoint implementation add AgentState and Checkpointer serializer add support for MemorySaver work on #11 --- .../org/bsc/langgraph4j/CompileConfig.java | 2 +- .../org/bsc/langgraph4j/CompiledGraph.java | 1 + .../org/bsc/langgraph4j/InvokeConfig.java | 2 +- .../java/org/bsc/langgraph4j/StateGraph.java | 2 + .../BaseCheckpointSaver.java | 6 +- .../{state => checkpoint}/Checkpoint.java | 25 ++++++- .../CheckpointConfig.java | 2 +- .../langgraph4j/checkpoint/MemorySaver.java | 31 ++++++++ .../serializer/AgentStateSerializer.java | 74 +++++++++++++++++++ .../serializer/CheckpointSerializer.java | 31 ++++++++ .../langgraph4j/serializer/Serializer.java | 40 ++++++++++ .../org/bsc/langgraph4j/SerializeTest.java | 72 ++++++++++++++++++ 12 files changed, 279 insertions(+), 9 deletions(-) rename core-jdk8/src/main/java/org/bsc/langgraph4j/{state => checkpoint}/BaseCheckpointSaver.java (58%) rename core-jdk8/src/main/java/org/bsc/langgraph4j/{state => checkpoint}/Checkpoint.java (52%) rename core-jdk8/src/main/java/org/bsc/langgraph4j/{state => checkpoint}/CheckpointConfig.java (73%) create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/AgentStateSerializer.java create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java create mode 100644 core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/Serializer.java create mode 100644 core-jdk8/src/test/java/org/bsc/langgraph4j/SerializeTest.java diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java index 2ca5415..d6d2f79 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompileConfig.java @@ -1,6 +1,6 @@ package org.bsc.langgraph4j; -import org.bsc.langgraph4j.state.BaseCheckpointSaver; +import org.bsc.langgraph4j.checkpoint.BaseCheckpointSaver; import java.util.Optional; diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java index e205b89..2eb1a70 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java @@ -116,6 +116,7 @@ private String getEntryPoint( State state ) throws Exception { * @throws Exception if there is an error creating the stream */ public AsyncGenerator> stream(Map inputs, InvokeConfig config ) throws Exception { + Objects.requireNonNull(config, "config cannot be null"); return AsyncGeneratorQueue.of(new LinkedBlockingQueue<>(), queue -> { diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java index 1588a35..3fad8d9 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/InvokeConfig.java @@ -1,6 +1,6 @@ package org.bsc.langgraph4j; -import org.bsc.langgraph4j.state.CheckpointConfig; +import org.bsc.langgraph4j.checkpoint.CheckpointConfig; import java.util.Optional; diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java index 30ffa4d..c9fbbb2 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/StateGraph.java @@ -203,6 +203,8 @@ private Node makeFakeNode(String id) { * @throws GraphStateException if there are errors related to the graph state */ public CompiledGraph compile( CompileConfig config ) throws GraphStateException { + Objects.requireNonNull(config, "config cannot be null"); + if (entryPoint == null) { throw Errors.missingEntryPoint.exception(); } diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/BaseCheckpointSaver.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/BaseCheckpointSaver.java similarity index 58% rename from core-jdk8/src/main/java/org/bsc/langgraph4j/state/BaseCheckpointSaver.java rename to core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/BaseCheckpointSaver.java index 1877c76..1e65fc1 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/BaseCheckpointSaver.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/BaseCheckpointSaver.java @@ -1,11 +1,13 @@ -package org.bsc.langgraph4j.state; +package org.bsc.langgraph4j.checkpoint; +import java.io.Externalizable; import java.util.Collection; import java.util.Optional; public interface BaseCheckpointSaver { + Collection list(); Optional get( String id ); - void put( Checkpoint checkpoint ); + void put( Checkpoint checkpoint ) throws Exception; } diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/Checkpoint.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/Checkpoint.java similarity index 52% rename from core-jdk8/src/main/java/org/bsc/langgraph4j/state/Checkpoint.java rename to core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/Checkpoint.java index dad10fb..8b5f8e7 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/Checkpoint.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/Checkpoint.java @@ -1,9 +1,26 @@ -package org.bsc.langgraph4j.state; +package org.bsc.langgraph4j.checkpoint; -import lombok.Value; +import lombok.Data; +import org.bsc.langgraph4j.state.AgentState; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.util.*; + +/** + * Represents a checkpoint of an agent state. + * + * The checkpoint is an immutable object that holds an {@link AgentState} + * and a {@code String} that represents the next state. + * + * The checkpoint is serializable and can be persisted and restored. + * + * @see AgentState + * @see Externalizable + */ public class Checkpoint { @lombok.Value(staticConstructor="of") @@ -12,8 +29,8 @@ public static class Value { String next; } - private final String id; - private final Value value; + String id; + Value value; public final String getId() { return id; diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/CheckpointConfig.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/CheckpointConfig.java similarity index 73% rename from core-jdk8/src/main/java/org/bsc/langgraph4j/state/CheckpointConfig.java rename to core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/CheckpointConfig.java index 0b33249..77de6e7 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/CheckpointConfig.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/CheckpointConfig.java @@ -1,4 +1,4 @@ -package org.bsc.langgraph4j.state; +package org.bsc.langgraph4j.checkpoint; import lombok.Value; diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java new file mode 100644 index 0000000..4f3a093 --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java @@ -0,0 +1,31 @@ +package org.bsc.langgraph4j.checkpoint; + +import org.bsc.langgraph4j.serializer.CheckpointSerializer; + +import java.util.*; + +import static java.util.Collections.unmodifiableSet; + +public class MemorySaver implements BaseCheckpointSaver { + + private final Set checkpoints = new LinkedHashSet<>(); + + + @Override + public Collection list() { + return unmodifiableSet(checkpoints); // immutable checkpoints; + } + + @Override + public Optional get(String id) { + return checkpoints.stream() + .filter( checkpoint -> checkpoint.getId().equals(id) ) + .findFirst(); + } + + @Override + public void put(Checkpoint checkpoint) throws Exception { + checkpoints.add( CheckpointSerializer.INSTANCE.cloneObject(checkpoint) ); + } + +} diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/AgentStateSerializer.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/AgentStateSerializer.java new file mode 100644 index 0000000..08c1414 --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/AgentStateSerializer.java @@ -0,0 +1,74 @@ +package org.bsc.langgraph4j.serializer; + +import lombok.extern.log4j.Log4j; +import lombok.extern.slf4j.Slf4j; +import org.bsc.langgraph4j.state.AgentState; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class AgentStateSerializer implements Serializer { + public static final AgentStateSerializer INSTANCE = new AgentStateSerializer(); + private AgentStateSerializer() {} + + @Override + public void write(AgentState object, ObjectOutput out) throws IOException { + try( ByteArrayOutputStream baos = new ByteArrayOutputStream() ) { + int actuoalSize = 0; + + final ObjectOutputStream tupleStream = new ObjectOutputStream( baos ); + for( Map.Entry e : object.data().entrySet() ) { + try { + tupleStream.writeUTF(e.getKey()); + tupleStream.writeObject(e.getValue()); + ++actuoalSize; + } catch (IOException ex) { + log.error( "Error writing state key '{}' - {}", e.getKey(), ex.getMessage() ); + throw ex; + } + } + + out.writeInt( object.data().size() ); + out.writeInt( actuoalSize ); // actual size + byte[] data = baos.toByteArray(); + out.writeInt( data.length ); + out.write( data ); + + } + + } + + @Override + public AgentState read(ObjectInput in) throws IOException, ClassNotFoundException { + Map data = new HashMap<>(); + + int expectedSize = in.readInt(); + int actualSize = in.readInt(); + if( expectedSize > 0 && actualSize > 0 ) { + + if( expectedSize != actualSize ) { + final String message = String.format( "Deserialize State: Expected size %d and actual size %d do not match!", expectedSize, actualSize ) ; + log.error( message ) ; + throw new IOException( message ) ; + } + + int byteLen = in.readInt(); + byte[] bytes = new byte[byteLen]; + in.readFully(bytes); + + try( ByteArrayInputStream bais = new ByteArrayInputStream( bytes ) ) { + ObjectInputStream ois = new ObjectInputStream( bais ); + + for( int i = 0; i < actualSize; i++ ) { + String key = ois.readUTF(); + Object value = ois.readObject(); + data.put(key, value); + } + } + + } + return new AgentState(data); + } +} diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java new file mode 100644 index 0000000..cac4f8e --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java @@ -0,0 +1,31 @@ +package org.bsc.langgraph4j.serializer; + +import org.bsc.langgraph4j.checkpoint.Checkpoint; +import org.bsc.langgraph4j.state.AgentState; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +public class CheckpointSerializer implements Serializer { + + public static final CheckpointSerializer INSTANCE = new CheckpointSerializer(); + + private CheckpointSerializer() {} + + public void write( Checkpoint object, ObjectOutput out) throws IOException { + out.writeUTF(object.getId()); + Checkpoint.Value value = object.getValue(); + AgentStateSerializer.INSTANCE.write( value.getState(), out ); + out.writeUTF( value.getNext() ); + } + + public Checkpoint read(ObjectInput in) throws IOException, ClassNotFoundException { + String id = in.readUTF(); + AgentState state = AgentStateSerializer.INSTANCE.read( in ); + String next = in.readUTF(); + Checkpoint.Value value = Checkpoint.Value.of( state, next ); + return new Checkpoint(id, value); + } + +} diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/Serializer.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/Serializer.java new file mode 100644 index 0000000..15404f6 --- /dev/null +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/Serializer.java @@ -0,0 +1,40 @@ +package org.bsc.langgraph4j.serializer; + +import org.bsc.langgraph4j.checkpoint.Checkpoint; + +import java.io.*; +import java.util.Objects; + +public interface Serializer { + + void write(T object, ObjectOutput out) throws IOException; + + + T read(ObjectInput in) throws IOException, ClassNotFoundException ; + + default byte[] writeObject(T object) throws IOException { + Objects.requireNonNull( object, "object cannot be null" ); + try( ByteArrayOutputStream baos = new ByteArrayOutputStream() ) { + ObjectOutputStream oas = new ObjectOutputStream(baos); + write(object, oas); + oas.flush(); + return baos.toByteArray(); + } + } + + default T readObject(byte[] bytes) throws IOException, ClassNotFoundException { + Objects.requireNonNull( bytes, "bytes cannot be null" ); + if( bytes.length == 0 ) { + throw new IllegalArgumentException("bytes cannot be empty"); + } + try( ByteArrayInputStream bais = new ByteArrayInputStream( bytes ) ) { + ObjectInputStream ois = new ObjectInputStream(bais); + return read(ois); + } + } + + default T cloneObject(T object) throws IOException, ClassNotFoundException { + Objects.requireNonNull( object, "object cannot be null" ); + return readObject(writeObject(object)); + } +} diff --git a/core-jdk8/src/test/java/org/bsc/langgraph4j/SerializeTest.java b/core-jdk8/src/test/java/org/bsc/langgraph4j/SerializeTest.java new file mode 100644 index 0000000..4721afe --- /dev/null +++ b/core-jdk8/src/test/java/org/bsc/langgraph4j/SerializeTest.java @@ -0,0 +1,72 @@ +package org.bsc.langgraph4j; + +import org.bsc.langgraph4j.serializer.AgentStateSerializer; +import org.bsc.langgraph4j.state.AgentState; +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +public class SerializeTest { + + + private byte[] serializeState(AgentState state) throws Exception { + try( ByteArrayOutputStream baos = new ByteArrayOutputStream() ) { + ObjectOutputStream oas = new ObjectOutputStream(baos); + AgentStateSerializer.INSTANCE.write(state, oas); + oas.flush(); + return baos.toByteArray(); + } + } + private AgentState deserializeState( byte[] bytes ) throws Exception { + try(ByteArrayInputStream bais = new ByteArrayInputStream( bytes ) ) { + ObjectInputStream ois = new ObjectInputStream( bais ); + return AgentStateSerializer.INSTANCE.read( ois ); + } + } + + @Test + public void serializeStateTest() throws Exception { + + Map data = new HashMap<>(); + data.put("a", "b"); + data.put("f", null); + data.put("c", "d"); + + final AgentState state = new AgentState(data); + + byte[] bytes = serializeState(state); + + assertNotNull(bytes); + AgentState deserializeState = deserializeState( bytes ); + + assertEquals( 3, deserializeState.data().size() ); + assertEquals( "b", deserializeState.data().get("a") ); + assertEquals( "d", deserializeState.data().get("c") ); + } + + static class NonSerializableElement { + String value = "TEST"; + public NonSerializableElement() { + } + } + @Test + public void partiallySerializeStateTest() throws Exception { + + Map data = new HashMap<>(); + data.put("a", "b"); + data.put("f", new NonSerializableElement() ); + data.put("c", "d"); + + final AgentState state = new AgentState(data); + + assertThrows(IOException.class, () -> { + serializeState(state); + }); + + } + +} From a49decf1386fedd1bf28ec417f19ee53847ee939 Mon Sep 17 00:00:00 2001 From: bsorrentino Date: Wed, 7 Aug 2024 14:18:38 +0200 Subject: [PATCH 4/7] refactor: make AppendableValueRW serializable work on #11 --- .../langgraph4j/state/AppendableValueRW.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/AppendableValueRW.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/AppendableValueRW.java index ed8e965..aa277b3 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/state/AppendableValueRW.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/state/AppendableValueRW.java @@ -1,5 +1,9 @@ package org.bsc.langgraph4j.state; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.util.*; import static java.util.Collections.unmodifiableList; @@ -10,8 +14,8 @@ * * @param the type of the value */ -public class AppendableValueRW implements AppendableValue { - private final List values; +public class AppendableValueRW implements AppendableValue, Externalizable { + private List values; /** * Constructs an AppendableValueRW with the given initial collection of values. @@ -100,4 +104,14 @@ public Optional lastMinus(int n) { public String toString() { return String.valueOf(values); } + + @Override + public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(values); + } + + @Override + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + values = (List) in.readObject(); + } } From 77e4723753a79b1cb8d6a0e7b05c9da97216e93b Mon Sep 17 00:00:00 2001 From: bsorrentino Date: Wed, 7 Aug 2024 14:21:30 +0200 Subject: [PATCH 5/7] feat: finalize Checkpoint implementation resolve #11 --- .../org/bsc/langgraph4j/CompiledGraph.java | 29 +++- .../checkpoint/BaseCheckpointSaver.java | 2 +- .../langgraph4j/checkpoint/Checkpoint.java | 2 +- .../langgraph4j/checkpoint/MemorySaver.java | 12 +- .../serializer/CheckpointSerializer.java | 6 +- .../org/bsc/langgraph4j/StateGraphTest.java | 145 +++++++++++++++++- 6 files changed, 186 insertions(+), 10 deletions(-) diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java index 2eb1a70..6b4c4c9 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/CompiledGraph.java @@ -6,6 +6,8 @@ import org.bsc.async.AsyncGenerator; import org.bsc.async.AsyncGeneratorQueue; import org.bsc.langgraph4j.action.AsyncNodeAction; +import org.bsc.langgraph4j.checkpoint.BaseCheckpointSaver; +import org.bsc.langgraph4j.checkpoint.Checkpoint; import org.bsc.langgraph4j.state.AgentState; import java.util.*; @@ -107,6 +109,26 @@ private String getEntryPoint( State state ) throws Exception { return nextNodeId(stateGraph.getEntryPoint(), state, "entryPoint"); } + private void addCheckpoint( String nodeId, State state ) throws Exception { + if( compileConfig.getCheckpointSaver().isPresent() ) { + Checkpoint.Value value = Checkpoint.Value.of(state, nodeId); + compileConfig.getCheckpointSaver().get().put( new Checkpoint(value) ); + } + } + + State getInitialState(Map inputs) { + + return compileConfig.getCheckpointSaver() + .flatMap(BaseCheckpointSaver::getLast) + .map( cp -> { + var state = cp.getValue().getState(); + return state.mergeWith(inputs, stateGraph.getStateFactory()); + }) + .orElseGet( () -> + stateGraph.getStateFactory().apply(inputs) + ); + } + /** * Creates an AsyncGenerator stream of NodeOutput based on the provided inputs. * @@ -121,9 +143,12 @@ public AsyncGenerator> stream(Map inputs, Invok return AsyncGeneratorQueue.of(new LinkedBlockingQueue<>(), queue -> { try { - var currentState = stateGraph.getStateFactory().apply(inputs); + + var currentState = getInitialState(inputs); queue.add( AsyncGenerator.Data.of( completedFuture( NodeOutput.of("start", currentState)) )); + addCheckpoint( "start", currentState ); + log.trace( "START"); var currentNodeId = this.getEntryPoint( currentState ); @@ -146,6 +171,7 @@ public AsyncGenerator> stream(Map inputs, Invok currentState = currentState.mergeWith(partialState, stateGraph.getStateFactory()); queue.add( AsyncGenerator.Data.of( completedFuture( NodeOutput.of(currentNodeId, currentState) ) )); + addCheckpoint( currentNodeId, currentState ); if ( Objects.equals(currentNodeId, stateGraph.getFinishPoint()) ) { break; @@ -165,6 +191,7 @@ public AsyncGenerator> stream(Map inputs, Invok } queue.add( AsyncGenerator.Data.of( completedFuture( NodeOutput.of("stop", currentState) ) )); + addCheckpoint( "stop", currentState ); log.trace( "STOP"); } catch (Exception e) { diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/BaseCheckpointSaver.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/BaseCheckpointSaver.java index 1e65fc1..85652a7 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/BaseCheckpointSaver.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/BaseCheckpointSaver.java @@ -8,6 +8,6 @@ public interface BaseCheckpointSaver { Collection list(); - Optional get( String id ); + Optional getLast(); void put( Checkpoint checkpoint ) throws Exception; } diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/Checkpoint.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/Checkpoint.java index 8b5f8e7..fd3a6e8 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/Checkpoint.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/Checkpoint.java @@ -26,7 +26,7 @@ public class Checkpoint { @lombok.Value(staticConstructor="of") public static class Value { AgentState state; - String next; + String nodeId; } String id; diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java index 4f3a093..eea17cf 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/checkpoint/MemorySaver.java @@ -4,19 +4,27 @@ import java.util.*; +import static java.util.Collections.unmodifiableCollection; import static java.util.Collections.unmodifiableSet; public class MemorySaver implements BaseCheckpointSaver { - private final Set checkpoints = new LinkedHashSet<>(); + private final Stack checkpoints = new Stack<>(); @Override public Collection list() { - return unmodifiableSet(checkpoints); // immutable checkpoints; + return unmodifiableCollection(checkpoints); // immutable checkpoints; } @Override + public Optional getLast() { + if( checkpoints.isEmpty() ) { + return Optional.empty(); + } + return Optional.ofNullable( checkpoints.peek() ); + } + public Optional get(String id) { return checkpoints.stream() .filter( checkpoint -> checkpoint.getId().equals(id) ) diff --git a/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java index cac4f8e..ba2a725 100644 --- a/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java +++ b/core-jdk8/src/main/java/org/bsc/langgraph4j/serializer/CheckpointSerializer.java @@ -17,14 +17,14 @@ public void write( Checkpoint object, ObjectOutput out) throws IOException { out.writeUTF(object.getId()); Checkpoint.Value value = object.getValue(); AgentStateSerializer.INSTANCE.write( value.getState(), out ); - out.writeUTF( value.getNext() ); + out.writeUTF( value.getNodeId() ); } public Checkpoint read(ObjectInput in) throws IOException, ClassNotFoundException { String id = in.readUTF(); AgentState state = AgentStateSerializer.INSTANCE.read( in ); - String next = in.readUTF(); - Checkpoint.Value value = Checkpoint.Value.of( state, next ); + String nodeId = in.readUTF(); + Checkpoint.Value value = Checkpoint.Value.of( state, nodeId ); return new Checkpoint(id, value); } diff --git a/core-jdk8/src/test/java/org/bsc/langgraph4j/StateGraphTest.java b/core-jdk8/src/test/java/org/bsc/langgraph4j/StateGraphTest.java index 55406f5..d3cb7e7 100644 --- a/core-jdk8/src/test/java/org/bsc/langgraph4j/StateGraphTest.java +++ b/core-jdk8/src/test/java/org/bsc/langgraph4j/StateGraphTest.java @@ -1,13 +1,17 @@ package org.bsc.langgraph4j; import lombok.var; +import org.bsc.langgraph4j.checkpoint.Checkpoint; +import org.bsc.langgraph4j.checkpoint.MemorySaver; import org.bsc.langgraph4j.state.AgentState; +import org.bsc.langgraph4j.state.AppendableValue; import org.junit.jupiter.api.Test; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; +import static java.lang.String.format; +import static java.util.Collections.emptyMap; import static org.bsc.langgraph4j.StateGraph.END; import static org.bsc.langgraph4j.action.AsyncEdgeAction.edge_async; import static org.bsc.langgraph4j.action.AsyncNodeAction.node_async; @@ -104,5 +108,142 @@ public void testRunningOneNode() throws Exception { } + @Test + public void testCheckpointInitialState() throws Exception { + + var workflow = new StateGraph<>(AgentState::new); + workflow.setEntryPoint("agent_1"); + + workflow.addNode("agent_1", node_async( state -> { + System.out.print( "agent_1"); + return mapOf("agent_1:prop1", "agent_1:test"); + })); + + workflow.addEdge( "agent_1", END); + + var saver = new MemorySaver(); + + var compileConfig = CompileConfig.builder().checkpointSaver(saver).build(); + + var app = workflow.compile( compileConfig ); + + Map inputs = mapOf( "input", "test1"); + + var initState = app.getInitialState( inputs ); + + assertEquals( 1, initState.data().size() ); + assertTrue( initState.value("input").isPresent() ); + assertEquals( "test1", initState.value("input").get() ); + + // + // Test checkpoint not override inputs + // + var newState = new AgentState( mapOf( "input", "test2") ); + saver.put( new Checkpoint( Checkpoint.Value.of( newState, "start" ) ) ); + + app = workflow.compile( compileConfig ); + initState = app.getInitialState( inputs ); + + assertEquals( 1, initState.data().size() ); + assertTrue( initState.value("input").isPresent() ); + assertEquals( "test1", initState.value("input").get() ); + + // Test checkpoints are saved + newState = new AgentState( mapOf( "input", "test2", "agent_1:prop1", "agent_1:test") ); + saver.put( new Checkpoint( Checkpoint.Value.of( newState, "agent_1" ) ) ); + + app = workflow.compile( compileConfig ); + initState = app.getInitialState( inputs ); + + assertEquals( 2, initState.data().size() ); + assertTrue( initState.value("input").isPresent() ); + assertEquals( "test1", initState.value("input").get() ); + assertTrue( initState.value("agent_1:prop1").isPresent() ); + assertEquals( "agent_1:test", initState.value("agent_1:prop1").get() ); + + var checkpoints = saver.list(); + assertEquals( 2, checkpoints.size() ); + var last = saver.getLast(); + assertTrue( last.isPresent() ); + assertEquals( "agent_1", last.get().getValue().getNodeId() ); + assertTrue( last.get().getValue().getState().value("agent_1:prop1").isPresent() ); + assertEquals( "agent_1:test", last.get().getValue().getState().value("agent_1:prop1").get() ); + + } + + static class MessagesState extends AgentState { + + public MessagesState(Map initData) { + super( initData ); + appendableValue("messages"); // tip: initialize messages + } + + int steps() { + return value("steps").map(Integer.class::cast).orElse(0); + } + + AppendableValue messages() { + return appendableValue("messages"); + } + + } + + @Test + public void testCheckpointSaver() throws Exception { + var STEPS_COUNT = 5; + + var workflow = new StateGraph<>(MessagesState::new); + workflow.setEntryPoint("agent_1"); + + workflow.addNode("agent_1", node_async( state -> { + + System.out.println( "agent_1"); + var steps = state.steps() + 1; + return mapOf("steps", steps, "messages", format( "agent_1:step %d", steps )); + })); + workflow.addConditionalEdges( "agent_1", edge_async( state -> { + var steps = state.steps(); + if( steps >= STEPS_COUNT) { + return "exit"; + } + return "next"; + }), mapOf( "next", "agent_1", "exit", END) ); + + var saver = new MemorySaver(); + + var compileConfig = CompileConfig.builder() + .checkpointSaver(saver) + .build(); + + var app = workflow.compile( compileConfig ); + + Map inputs = mapOf( "steps", 0 ); + + var invokeConfig = InvokeConfig.builder().checkpointThreadId("thread_1").build(); + + var state = app.invoke( inputs, invokeConfig ); + + assertTrue( state.isPresent() ); + assertEquals( STEPS_COUNT, state.get().steps() ); + var messages = state.get().appendableValue("messages"); + assertFalse( messages.isEmpty() ); + + System.out.println( messages.values() ); + + assertEquals( STEPS_COUNT, messages.size() ); + for( int i = 0; i < messages.size(); i++ ) { + assertEquals( format("agent_1:step %d", i+1), messages.values().get(i) ); + } + + state = app.invoke( emptyMap(), invokeConfig ); + + assertTrue( state.isPresent() ); + assertEquals( STEPS_COUNT + 1, state.get().steps() ); + messages = state.get().appendableValue("messages"); + assertEquals( STEPS_COUNT + 1, messages.size() ); + for( int i = 0; i < messages.size(); i++ ) { + assertEquals( format("agent_1:step %d", i+1), messages.values().get(i) ); + } + } } From 93074fbd0e0beef4d84284d290910ebc2e499415 Mon Sep 17 00:00:00 2001 From: bsorrentino Date: Wed, 7 Aug 2024 14:48:58 +0200 Subject: [PATCH 6/7] ci: add deploy snapshot action --- .github/workflows/deploy-snapshot.yaml | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/deploy-snapshot.yaml diff --git a/.github/workflows/deploy-snapshot.yaml b/.github/workflows/deploy-snapshot.yaml new file mode 100644 index 0000000..41d1176 --- /dev/null +++ b/.github/workflows/deploy-snapshot.yaml @@ -0,0 +1,42 @@ +name: Deploy New Version + +on: + workflow_dispatch: + release: + types: [created] + +jobs: + deploy: + runs-on: ubuntu-latest + name: deploy + steps: + - uses: actions/checkout@v4 + with: + ref: main + - name: GPG Setup + env: + GPG_KEY_BASE64: ${{ secrets.GPG_KEY_BASE64 }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: ./gpg-setup.sh + - name: Set up JDK 8 + uses: actions/setup-java@v4 + with: + distribution: 'liberica' + java-version: '8' + java-package: jdk + - name: Deploy to OSS Sonatype + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OSS_SONATYPE_TOKEN: ${{ secrets.OSS_SONATYPE_TOKEN }} + run: mvn -B -Prelease source:jar javadoc:jar deploy --file pom.xml -s settings-template.xml -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: 'liberica' + java-version: '17' + java-package: jdk + - name: Deploy to OSS Sonatype + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OSS_SONATYPE_TOKEN: ${{ secrets.OSS_SONATYPE_TOKEN }} + run: mvn -B -Prelease -pl server-jetty source:jar javadoc:jar deploy --file pom.xml -s settings-template.xml -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} From 5db6022ca33092780e0072075d144a70d73316e0 Mon Sep 17 00:00:00 2001 From: bsorrentino Date: Wed, 7 Aug 2024 14:49:15 +0200 Subject: [PATCH 7/7] build: move to next developer release --- .github/workflows/deploy-snapshot.yaml | 34 +++++++++++++++----------- adaptive-rag/pom.xml | 2 +- agent-executor/pom.xml | 2 +- core-jdk8/pom.xml | 2 +- image-to-diagram/pom.xml | 2 +- pom.xml | 2 +- server-jetty/pom.xml | 2 +- 7 files changed, 26 insertions(+), 20 deletions(-) diff --git a/.github/workflows/deploy-snapshot.yaml b/.github/workflows/deploy-snapshot.yaml index 41d1176..9a4d506 100644 --- a/.github/workflows/deploy-snapshot.yaml +++ b/.github/workflows/deploy-snapshot.yaml @@ -2,9 +2,11 @@ name: Deploy New Version on: workflow_dispatch: - release: - types: [created] - + push: + branches: + - main + paths: + - '**/pom.xml' jobs: deploy: runs-on: ubuntu-latest @@ -13,30 +15,34 @@ jobs: - uses: actions/checkout@v4 with: ref: main - - name: GPG Setup - env: - GPG_KEY_BASE64: ${{ secrets.GPG_KEY_BASE64 }} - GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - run: ./gpg-setup.sh - name: Set up JDK 8 uses: actions/setup-java@v4 with: distribution: 'liberica' java-version: '8' java-package: jdk - - name: Deploy to OSS Sonatype + - name: Check for SNAPSHOT version + id: check-snapshot + run: | + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + if [[ $VERSION == *"-SNAPSHOT" ]]; then + echo "::set-output name=is_snapshot::true" + else + echo "::set-output name=is_snapshot::false" + fi + - name: Build and Deploy SNAPSHOT + if: steps.check-snapshot.outputs.is_snapshot == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OSS_SONATYPE_TOKEN: ${{ secrets.OSS_SONATYPE_TOKEN }} - run: mvn -B -Prelease source:jar javadoc:jar deploy --file pom.xml -s settings-template.xml -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} + run: mvn -B clean deploy --file pom.xml -s settings-template.xml - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: 'liberica' java-version: '17' java-package: jdk - - name: Deploy to OSS Sonatype + - name: Build and Deploy SNAPSHOT + if: steps.check-snapshot.outputs.is_snapshot == 'true' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OSS_SONATYPE_TOKEN: ${{ secrets.OSS_SONATYPE_TOKEN }} - run: mvn -B -Prelease -pl server-jetty source:jar javadoc:jar deploy --file pom.xml -s settings-template.xml -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} + run: mvn -B -pl server-jetty clean deploy --file pom.xml -s settings-template.xml diff --git a/adaptive-rag/pom.xml b/adaptive-rag/pom.xml index 3df6e43..05a26ce 100644 --- a/adaptive-rag/pom.xml +++ b/adaptive-rag/pom.xml @@ -4,7 +4,7 @@ org.bsc.langgraph4j langgraph4j-parent - 1.0-beta1 + 1.0-SNAPSHOT langgraph4j-adaptive-rag diff --git a/agent-executor/pom.xml b/agent-executor/pom.xml index a59d6fc..fd620b0 100644 --- a/agent-executor/pom.xml +++ b/agent-executor/pom.xml @@ -4,7 +4,7 @@ org.bsc.langgraph4j langgraph4j-parent - 1.0-beta1 + 1.0-SNAPSHOT langgraph4j-agent-executor diff --git a/core-jdk8/pom.xml b/core-jdk8/pom.xml index a543f47..da1bc0e 100644 --- a/core-jdk8/pom.xml +++ b/core-jdk8/pom.xml @@ -5,7 +5,7 @@ org.bsc.langgraph4j langgraph4j-parent - 1.0-beta1 + 1.0-SNAPSHOT langgraph4j-core-jdk8 diff --git a/image-to-diagram/pom.xml b/image-to-diagram/pom.xml index 4d22533..e396750 100644 --- a/image-to-diagram/pom.xml +++ b/image-to-diagram/pom.xml @@ -4,7 +4,7 @@ org.bsc.langgraph4j langgraph4j-parent - 1.0-beta1 + 1.0-SNAPSHOT langgraph4j-image-to-diagram diff --git a/pom.xml b/pom.xml index 630bc22..99cb11a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.bsc.langgraph4j langgraph4j-parent - 1.0-beta1 + 1.0-SNAPSHOT pom langgraph4j::parent diff --git a/server-jetty/pom.xml b/server-jetty/pom.xml index a85fff9..13d4f0b 100644 --- a/server-jetty/pom.xml +++ b/server-jetty/pom.xml @@ -6,7 +6,7 @@ org.bsc.langgraph4j langgraph4j-parent - 1.0-beta1 + 1.0-SNAPSHOT langgraph4j-server-jetty