Skip to content

Commit 3286b58

Browse files
committed
RDBC-926 Introduce AI agent management operations, including create, update, delete. Add AI conversation and agent operation tests, enhance error handling
1 parent 8230e78 commit 3286b58

27 files changed

+1055
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ old
2424
test_server_settings.json
2525
.nyc_output
2626
coverage
27+
RavenDB/**/*
28+
.env
29+
certs/**/*

src/Documents/DocumentStoreBase.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { IAbstractIndexCreationTask } from "./Indexes/IAbstractIndexCreationTask
3939
import { StringUtil } from "../Utility/StringUtil.js";
4040
import { IHiLoIdGenerator } from "./Identity/IHiLoIdGenerator.js";
4141
import { BulkInsertOptions } from "./BulkInsert/BulkInsertOptions.js";
42+
import { AiOperations } from "./Operations/AI/AiOperations.js";
4243

4344
export abstract class DocumentStoreBase
4445
extends EventEmitter
@@ -112,6 +113,16 @@ export abstract class DocumentStoreBase
112113

113114
private _conventions: DocumentConventions;
114115

116+
private _aiOperations: AiOperations;
117+
118+
public get ai() {
119+
if (!this._aiOperations) {
120+
this._aiOperations = new AiOperations(this);
121+
}
122+
123+
return this._aiOperations;
124+
}
125+
115126
public get conventions() {
116127
if (!this._conventions) {
117128
this._conventions = new DocumentConventions();

src/Documents/IDocumentStore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { IAbstractIndexCreationTask } from "./Indexes/IAbstractIndexCreationTask
2727
import { TimeSeriesOperations } from "./TimeSeries/TimeSeriesOperations.js";
2828
import { IHiLoIdGenerator } from "./Identity/IHiLoIdGenerator.js";
2929
import { BulkInsertOptions } from "./BulkInsert/BulkInsertOptions.js";
30+
import { AiOperations } from "./Operations/AI/AiOperations.js";
3031

3132
export interface SessionEventsProxy {
3233
addSessionListener(eventName: "failedRequest", eventHandler: (eventArgs: FailedRequestEventArgs) => void): this;
@@ -245,6 +246,7 @@ export interface IDocumentStore extends IDisposable,
245246

246247
timeSeries: TimeSeriesOperations;
247248

249+
ai: AiOperations;
248250
/**
249251
* Gets the conventions
250252
*/
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { IMaintenanceOperation, OperationResultType } from "../../OperationAbstractions.js";
2+
import { Stream } from "node:stream";
3+
import type { AiAgentConfiguration } from "./config/AiAgentConfiguration.js";
4+
import type { AiAgentConfigurationResult } from "./AiAgentConfigurationResult.js";
5+
import { RavenCommand } from "../../../../Http/RavenCommand.js";
6+
import { DocumentConventions } from "../../../Conventions/DocumentConventions.js";
7+
import { IRaftCommand } from "../../../../Http/IRaftCommand.js";
8+
import { ServerNode } from "../../../../Http/ServerNode.js";
9+
import { HttpRequestParameters } from "../../../../Primitives/Http.js";
10+
import { RaftIdGenerator } from "../../../../Utility/RaftIdGenerator.js";
11+
import { throwError } from "../../../../Exceptions/index.js";
12+
import { ObjectUtil } from "../../../../Utility/ObjectUtil.js";
13+
import { JsonSerializer } from "../../../../Mapping/Json/Serializer.js";
14+
import { HeadersBuilder } from "../../../../Utility/HttpUtil.js";
15+
16+
function hasNoSampleObjectOrSchema(configuration: AiAgentConfiguration) {
17+
return (!configuration.outputSchema || configuration.outputSchema.trim() === "")
18+
&& (!configuration.sampleObject || configuration.sampleObject.trim() === "");
19+
}
20+
21+
export class AddOrUpdateAiAgentOperation implements IMaintenanceOperation<AiAgentConfigurationResult> {
22+
private readonly _configuration: AiAgentConfiguration;
23+
private readonly _sampleObject?: unknown;
24+
25+
public constructor(configuration: AiAgentConfiguration, schemaType?: any) {
26+
if (!configuration) {
27+
throwError("InvalidArgumentException", "configuration cannot be null or undefined.");
28+
}
29+
30+
if (!configuration.outputSchema && !configuration.sampleObject && !schemaType) {
31+
throwError("InvalidArgumentException", "Please provide a non-empty value for either outputSchema or sampleObject.");
32+
}
33+
this._configuration = configuration;
34+
if (schemaType) {
35+
this._sampleObject = schemaType;
36+
}
37+
}
38+
39+
public get resultType(): OperationResultType {
40+
return "CommandResult";
41+
}
42+
43+
public getCommand(conventions: DocumentConventions): RavenCommand<AiAgentConfigurationResult> {
44+
return new AddOrUpdateAiAgentCommand(this._configuration, this._sampleObject, conventions);
45+
}
46+
}
47+
48+
49+
class AddOrUpdateAiAgentCommand extends RavenCommand<AiAgentConfigurationResult> implements IRaftCommand {
50+
private readonly _configuration: AiAgentConfiguration;
51+
private readonly _conventions: DocumentConventions;
52+
private readonly _sampleSchema?: any;
53+
54+
public constructor(configuration: AiAgentConfiguration, sampleSchema: any, conventions: DocumentConventions) {
55+
super();
56+
if (hasNoSampleObjectOrSchema(configuration)) {
57+
throw new Error("Please provide a non-empty value for either outputSchema or sampleObject.");
58+
}
59+
this._configuration = configuration;
60+
this._sampleSchema = sampleSchema;
61+
this._conventions = conventions;
62+
}
63+
64+
get isReadRequest(): boolean {
65+
return false;
66+
}
67+
68+
getRaftUniqueRequestId(): string {
69+
return RaftIdGenerator.newId();
70+
}
71+
72+
createRequest(node: ServerNode): HttpRequestParameters {
73+
const uri = node.url + "/databases/" + node.database + "/admin/ai/agent";
74+
const configToSend = {...this._configuration};
75+
76+
if (!configToSend.sampleObject && this._sampleSchema) {
77+
configToSend.sampleObject = this._sampleSchema;
78+
}
79+
80+
const bodyToSerialize = {
81+
...configToSend,
82+
parameters: configToSend.parameters ? Array.from(configToSend.parameters) : []
83+
};
84+
85+
const bodyJson = ObjectUtil.transformObjectKeys(bodyToSerialize, {
86+
defaultTransform: ObjectUtil.pascal
87+
});
88+
89+
const body = JsonSerializer.getDefault().serialize(bodyJson);
90+
91+
const headers = HeadersBuilder
92+
.create()
93+
.typeAppJson()
94+
.build();
95+
96+
console.log(uri);
97+
return {
98+
method: "PUT",
99+
uri,
100+
body,
101+
headers
102+
} as HttpRequestParameters;
103+
}
104+
105+
async setResponseAsync(bodyStream: Stream, fromCache: boolean): Promise<string> {
106+
if (!bodyStream) {
107+
this._throwInvalidResponse();
108+
}
109+
let body = "";
110+
const data = await this._defaultPipeline<any>(_ => body = _).process(bodyStream);
111+
this.result = {
112+
identifier: data?.Identifier ?? data?.identifier,
113+
raftCommandIndex: data?.RaftCommandIndex ?? data?.raftCommandIndex
114+
} as AiAgentConfigurationResult;
115+
return body;
116+
}
117+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export interface AiAgentActionRequest {
2+
name: string;
3+
toolId: string;
4+
arguments: string; // JSON string provided by the model
5+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface AiAgentActionResponse {
2+
toolId: string;
3+
content: string; // JSON/string content provided back to the agent
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface AiAgentConfigurationResult {
2+
identifier: string;
3+
raftCommandIndex: number;
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface AiAgentParameter {
2+
name: string;
3+
description?: string;
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export interface AiAgentToolAction {
2+
name: string;
3+
description: string;
4+
parametersSampleObject?: string; // JSON string example
5+
parametersSchema?: string; // JSON schema string
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export interface AiAgentToolQuery {
2+
name: string;
3+
description: string;
4+
query: string;
5+
parametersSampleObject?: string; // JSON example of parameters
6+
parametersSchema?: string; // JSON schema for parameters
7+
}

0 commit comments

Comments
 (0)