Skip to content

Commit a6ff058

Browse files
authored
Merge pull request #490 from M4xymm/RDBC-926
RDBC-926 AI Agents - Node.js
2 parents 8230e78 + f43e2e5 commit a6ff058

32 files changed

+986
-7
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/**/*

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ravendb",
3-
"version": "7.0.1",
3+
"version": "7.1.0",
44
"description": "RavenDB client for Node.js",
55
"files": [
66
"dist"

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: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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 { HeadersBuilder } from "../../../../Utility/HttpUtil.js";
13+
14+
function hasNoSampleObjectAndSchema(configuration: AiAgentConfiguration) {
15+
return (!configuration.outputSchema || configuration.outputSchema.trim() === "")
16+
&& (!configuration.sampleObject || configuration.sampleObject.trim() === "");
17+
}
18+
19+
export class AddOrUpdateAiAgentOperation implements IMaintenanceOperation<AiAgentConfigurationResult> {
20+
private readonly _configuration: AiAgentConfiguration;
21+
private readonly _sampleObject?: unknown;
22+
23+
public constructor(configuration: AiAgentConfiguration, sampleObject?: any) {
24+
if (!configuration) {
25+
throwError("InvalidArgumentException", "configuration cannot be null or undefined.");
26+
}
27+
28+
if (hasNoSampleObjectAndSchema(configuration) && !sampleObject) {
29+
throwError("InvalidArgumentException", "Please provide a non-empty value for either outputSchema or sampleObject.");
30+
}
31+
this._configuration = configuration;
32+
if (sampleObject) {
33+
this._sampleObject = sampleObject;
34+
}
35+
}
36+
37+
public get resultType(): OperationResultType {
38+
return "CommandResult";
39+
}
40+
41+
public getCommand(conventions: DocumentConventions): RavenCommand<AiAgentConfigurationResult> {
42+
return new AddOrUpdateAiAgentCommand(this._configuration, this._sampleObject, conventions);
43+
}
44+
}
45+
46+
47+
class AddOrUpdateAiAgentCommand extends RavenCommand<AiAgentConfigurationResult> implements IRaftCommand {
48+
private readonly _configuration: AiAgentConfiguration;
49+
private readonly _conventions: DocumentConventions;
50+
private readonly _sampleSchema?: any;
51+
52+
public constructor(configuration: AiAgentConfiguration, sampleSchema: any, conventions: DocumentConventions) {
53+
super();
54+
if (hasNoSampleObjectAndSchema(configuration)) {
55+
throwError("InvalidArgumentException", "Please provide a non-empty value for either outputSchema or sampleObject.");
56+
}
57+
this._configuration = configuration;
58+
this._sampleSchema = sampleSchema;
59+
this._conventions = conventions;
60+
}
61+
62+
get isReadRequest(): boolean {
63+
return false;
64+
}
65+
66+
getRaftUniqueRequestId(): string {
67+
return RaftIdGenerator.newId();
68+
}
69+
70+
createRequest(node: ServerNode): HttpRequestParameters {
71+
const uri = node.url + "/databases/" + node.database + "/admin/ai/agent";
72+
73+
if (!this._configuration && this._sampleSchema) {
74+
this._configuration.sampleObject = this._sampleSchema;
75+
}
76+
77+
const body = this._serializer.serialize(this._configuration);
78+
79+
const headers = HeadersBuilder
80+
.create()
81+
.typeAppJson()
82+
.build();
83+
84+
return {
85+
method: "PUT",
86+
uri,
87+
body,
88+
headers
89+
} as HttpRequestParameters;
90+
}
91+
92+
async setResponseAsync(bodyStream: Stream, fromCache: boolean): Promise<string> {
93+
if (!bodyStream) {
94+
this._throwInvalidResponse();
95+
}
96+
97+
return this._parseResponseDefaultAsync(bodyStream);
98+
}
99+
}
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+
}

0 commit comments

Comments
 (0)