-
Notifications
You must be signed in to change notification settings - Fork 16
RDBC-959: Add AI agent feature #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v7.1
Are you sure you want to change the base?
Changes from 7 commits
bd23b75
db1aad7
36b9414
cdd9ab9
f331779
ee65ff8
28fbf7f
ad3fe10
a99bbae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| public class AiAnswer<TAnswer> { | ||
| private TAnswer answer; | ||
| private AiConversationResult status; | ||
|
|
||
| public AiAnswer() { | ||
| } | ||
|
|
||
| public AiAnswer(TAnswer answer, AiConversationResult status) { | ||
| this.answer = answer; | ||
| this.status = status; | ||
| } | ||
|
|
||
| public TAnswer getAnswer() { | ||
| return answer; | ||
| } | ||
|
|
||
| public void setAnswer(TAnswer answer) { | ||
| this.answer = answer; | ||
| } | ||
|
|
||
| public AiConversationResult getStatus() { | ||
| return status; | ||
| } | ||
|
|
||
| public void setStatus(AiConversationResult status) { | ||
| this.status = status; | ||
| } | ||
| } | ||
|
|
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| public class AiConversationCreationOptions { | ||
| private Map<String, Object> parameters; | ||
| private Integer expirationInSec; | ||
|
|
||
| public AiConversationCreationOptions() { | ||
| } | ||
|
|
||
| public AiConversationCreationOptions(Map<String, Object> parameters) { | ||
| this(parameters, null); | ||
| } | ||
|
|
||
| public AiConversationCreationOptions(Map<String, Object> parameters, Integer expirationInSec) { | ||
| this.parameters = parameters; | ||
| this.expirationInSec = expirationInSec; | ||
| } | ||
|
|
||
| public Map<String, Object> getParameters() { | ||
| return parameters; | ||
| } | ||
|
|
||
| public void setParameters(Map<String, Object> parameters) { | ||
| this.parameters = parameters; | ||
| } | ||
|
|
||
| public AiConversationCreationOptions addParameter(String name, Object value) { | ||
| if (this.parameters == null) { | ||
| this.parameters = new HashMap<>(); | ||
| } | ||
| this.parameters.put(name, value); | ||
| return this; | ||
| } | ||
|
|
||
| public Integer getExpirationInSec() { | ||
| return expirationInSec; | ||
| } | ||
|
|
||
| public void setExpirationInSec(Integer expirationInSec) { | ||
| this.expirationInSec = expirationInSec; | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| public enum AiConversationResult { | ||
| Done, | ||
| ActionRequired | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| public enum AiHandleErrorStrategy { | ||
| SendErrorsToModel, | ||
| RaiseImmediately | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| @FunctionalInterface | ||
| public interface AiHandler<TArgs> { | ||
| Object invoke(TArgs args); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| public class AiMessagePrompt { | ||
| class AiMessagePromptFields { | ||
| public static final String TEXT = "text"; | ||
| public static final String TYPE = "type"; | ||
| private AiMessagePromptFields() {} | ||
| } | ||
|
|
||
| class AiMessagePromptTypes { | ||
| public static final String TEXT = "text"; | ||
| private AiMessagePromptTypes() {} | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| import net.ravendb.client.documents.IDocumentStore; | ||
| import net.ravendb.client.documents.operations.AI.agents.*; | ||
| import net.ravendb.client.documents.operations.AI.agents.AiAgentConfiguration; | ||
| import net.ravendb.client.documents.operations.MaintenanceOperationExecutor; | ||
|
|
||
| public class AiOperations { | ||
| private final IDocumentStore store; | ||
| private final String databaseName; | ||
| private final MaintenanceOperationExecutor executor; | ||
|
|
||
| /** | ||
| * Initializes a new instance of AiOperations for a given document store and optional database name. | ||
| */ | ||
| public AiOperations(IDocumentStore store, String databaseName) { | ||
| this.store = store; | ||
| this.databaseName = databaseName; | ||
| this.executor = this.store.maintenance().forDatabase(this.databaseName); | ||
| } | ||
|
|
||
| public AiOperations(IDocumentStore store) { | ||
| this.store = store; | ||
| this.databaseName = store.getDatabase(); | ||
| this.executor = this.store.maintenance().forDatabase(this.databaseName); | ||
| } | ||
|
|
||
| /** | ||
| * Returns an AiOperations instance for a different database. | ||
| */ | ||
| public AiOperations forDatabase(String databaseName) { | ||
| if (this.databaseName.equalsIgnoreCase(databaseName)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this.databaseName can be NULL , if t will be you will get an exception
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| return this; | ||
| } | ||
| return new AiOperations(this.store, databaseName); | ||
| } | ||
|
|
||
| /** | ||
| * Creates or updates an AI agent configuration (with the given schema) on the database. | ||
| */ | ||
| public <TSchema> AiAgentConfigurationResult createAgent( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In C# we have as well
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| AiAgentConfiguration configuration, | ||
| TSchema sampleObject) { | ||
| AddOrUpdateAiAgentOperation operation = new AddOrUpdateAiAgentOperation(configuration, sampleObject); | ||
| return executor.send(operation); | ||
| } | ||
|
|
||
| /** | ||
| * Creates or updates an AI agent configuration (without given schema) on the database. | ||
| */ | ||
| public <TSchema> AiAgentConfigurationResult createAgent(AiAgentConfiguration configuration) { | ||
| AddOrUpdateAiAgentOperation operation = new AddOrUpdateAiAgentOperation(configuration); | ||
| return executor.send(operation); | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves the AI agent configuration for a specific agent. | ||
| */ | ||
| public AiAgentConfiguration getAgent(String agentId) { | ||
| GetAiAgentsOperation operation = new GetAiAgentsOperation(agentId); | ||
| GetAiAgentsResponse response = executor.send(operation); | ||
| if (response.getAiAgents() != null && !response.getAiAgents().isEmpty()) { | ||
| return response.getAiAgents().get(0); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves all AI agents and their configurations. | ||
| */ | ||
| public GetAiAgentsResponse getAgents() { | ||
| GetAiAgentsOperation operation = new GetAiAgentsOperation(); | ||
| return executor.send(operation); | ||
| } | ||
|
|
||
| /** | ||
| * Deletes an AI agent configuration. | ||
| */ | ||
| public AiAgentConfigurationResult deleteAgent(String identifier) { | ||
| DeleteAiAgentOperation operation = new DeleteAiAgentOperation(identifier); | ||
| return executor.send(operation); | ||
| } | ||
|
|
||
| /** | ||
| * Opens an AI conversation for an agent. | ||
| */ | ||
| public AiConversation conversation(String agentId, String conversationId, AiConversationCreationOptions creationOptions) { | ||
| return new AiConversation(store, databaseName, agentId, conversationId, creationOptions, null); | ||
| } | ||
|
|
||
| /** | ||
| * Opens an AI conversation for an agent. | ||
| */ | ||
| public AiConversation conversation(String agentId, String conversationId, | ||
| AiConversationCreationOptions creationOptions, | ||
| String changeVector) { | ||
| return new AiConversation(store, databaseName, agentId, conversationId, creationOptions, changeVector); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| /** | ||
| * Callback invoked with each streamed chunk from the AI agent response. | ||
| * The callback can be synchronous or asynchronous. | ||
| */ | ||
| @FunctionalInterface | ||
| public interface AiStreamCallback { | ||
|
|
||
| /** | ||
| * Handle a streamed text chunk from the AI agent. | ||
| * Implementations may process this synchronously or asynchronously. | ||
| * | ||
| * @param chunk The streamed text chunk from the specified property. | ||
| */ | ||
| CompletableFuture<Void> onChunk(String chunk); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import com.fasterxml.jackson.databind.node.ObjectNode; | ||
|
|
||
| public abstract class ContentPart { | ||
|
|
||
| @JsonProperty("type") | ||
| private final String type; | ||
|
|
||
| protected ContentPart(String type) { | ||
| this.type = type; | ||
| } | ||
|
|
||
| public String getType() { | ||
| return type; | ||
| } | ||
|
|
||
| public abstract ObjectNode toJson(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| import com.fasterxml.jackson.core.JsonProcessingException; | ||
| import net.ravendb.client.documents.operations.AI.agents.AiAgentActionRequest; | ||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| @FunctionalInterface | ||
| public interface IActionInvocation { | ||
| CompletableFuture<Void> invoke(AiAgentActionRequest request) throws JsonProcessingException; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| import com.fasterxml.jackson.databind.node.JsonNodeFactory; | ||
|
|
||
| public final class TextPart extends ContentPart { | ||
|
|
||
| @JsonProperty("text") | ||
| private String text; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we should add the annotation @notblank(message = "text cannot be null or blank") if we want to make sure it won't be null or empty or just spaces
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
|
||
| public TextPart(String text) { | ||
| super(AiMessagePrompt.AiMessagePromptTypes.TEXT); | ||
| this.text = text; | ||
| } | ||
|
|
||
| public String getText() { | ||
| return text; | ||
| } | ||
|
|
||
| public void setText(String text) { | ||
| this.text = text; | ||
| } | ||
|
|
||
| @Override | ||
| public ObjectNode toJson() { | ||
| ObjectNode json = JsonNodeFactory.instance.objectNode(); | ||
| json.put(AiMessagePrompt.AiMessagePromptFields.TYPE, getType()); | ||
| json.put(AiMessagePrompt.AiMessagePromptFields.TEXT, getText()); | ||
| return json; | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package net.ravendb.client.documents.AI; | ||
|
|
||
| import net.ravendb.client.documents.operations.AI.agents.AiAgentActionRequest; | ||
|
|
||
| /** | ||
| * Event arguments for an unhandled action in an AI agent conversation. | ||
| */ | ||
| public class UnhandledActionEventArgs { | ||
|
|
||
| private AiConversation sender; | ||
| private AiAgentActionRequest action; | ||
|
|
||
| public UnhandledActionEventArgs(AiConversation sender, AiAgentActionRequest action) { | ||
| this.action = action; | ||
| this.sender = sender; | ||
| } | ||
|
|
||
| public AiConversation getSender() { | ||
| return sender; | ||
| } | ||
|
|
||
| public void setSender(AiConversation sender) { | ||
| this.sender = sender; | ||
| } | ||
|
|
||
| public AiAgentActionRequest getAction() { | ||
| return action; | ||
| } | ||
|
|
||
| public void setAction(AiAgentActionRequest action) { | ||
| this.action = action; | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.