UNPKG

ravendb

Version:
150 lines 5.97 kB
import { Readable } from "node:stream"; import { createInterface } from "node:readline"; import { RavenCommand } from "../../../../Http/RavenCommand.js"; import { RaftIdGenerator } from "../../../../Utility/RaftIdGenerator.js"; import { throwError } from "../../../../Exceptions/index.js"; import { JsonSerializer } from "../../../../Mapping/Json/Serializer.js"; import { ObjectUtil } from "../../../../Utility/ObjectUtil.js"; import { StringUtil } from "../../../../Utility/StringUtil.js"; export class RunConversationOperation { _agentId; _conversationId; _userPrompt; _actionResponses; _options; _changeVector; _streamPropertyPath; _streamCallback; constructor(agentId, conversationId, userPrompt, actionResponses, options, changeVector, streamPropertyPath, streamCallback) { if (StringUtil.isNullOrEmpty(agentId)) { throwError("InvalidArgumentException", "agentId cannot be null or empty."); } if (StringUtil.isNullOrEmpty(conversationId)) { throwError("InvalidArgumentException", "conversationId cannot be null or empty."); } // Both streamPropertyPath and streamCallback must be specified together or neither if ((streamPropertyPath != null) !== (streamCallback != null)) { throwError("InvalidOperationException", "Both streamPropertyPath and streamCallback must be specified together or neither."); } this._agentId = agentId; this._conversationId = conversationId; this._userPrompt = userPrompt; this._actionResponses = actionResponses; this._options = options; this._changeVector = changeVector; this._streamPropertyPath = streamPropertyPath; this._streamCallback = streamCallback; } get resultType() { return "CommandResult"; } getCommand(conventions) { return new RunConversationCommand(this._conversationId, this._agentId, this._userPrompt, this._actionResponses, this._options, this._changeVector, conventions, this._streamPropertyPath, this._streamCallback); } } class RunConversationCommand extends RavenCommand { _conversationId; _agentId; _prompt; _actionResponses; _options; _changeVector; _streamPropertyPath; _streamCallback; _raftId; constructor(conversationId, agentId, prompt, actionResponses, options, changeVector, conventions, streamPropertyPath, streamCallback) { super(); this._conversationId = conversationId; this._agentId = agentId; this._prompt = prompt; this._actionResponses = actionResponses; this._options = options; this._changeVector = changeVector; this._streamPropertyPath = streamPropertyPath; this._streamCallback = streamCallback; // When streaming is enabled, we need to handle raw response if (this._streamPropertyPath && this._streamCallback) { this._responseType = "Raw"; } if (this._conversationId && this._conversationId.endsWith("|")) { this._raftId = RaftIdGenerator.newId(); } } get isReadRequest() { return false; } getRaftUniqueRequestId() { return this._raftId; } createRequest(node) { const uriParams = new URLSearchParams({ conversationId: this._conversationId, agentId: this._agentId, }); if (this._changeVector) { uriParams.append("changeVector", this._changeVector); } if (this._streamPropertyPath) { uriParams.append("streaming", "true"); uriParams.append("streamPropertyPath", this._streamPropertyPath); } const uri = `${node.url}/databases/${node.database}/ai/agent?${uriParams}`; const bodyObj = { ActionResponses: this._actionResponses, UserPrompt: this._prompt, CreationOptions: this._options ?? {} }; const headers = this._headers().typeAppJson().build(); // Serialize properties to PascalCase, except "parameters" in CreationOptions, which must keep user-provided, case-sensitive keys unchanged. const serialized = ObjectUtil.transformObjectKeys(bodyObj, { defaultTransform: ObjectUtil.pascalCase, ignorePaths: [ new RegExp("^CreationOptions\\.Parameters\\..*$") ] }); return { method: "POST", uri, headers, body: JsonSerializer.getDefault().serialize(serialized) }; } async setResponseAsync(bodyStream, fromCache) { if (!bodyStream) { this._throwInvalidResponse(); } if (this._streamPropertyPath && this._streamCallback) { return await this._processStreamingResponse(bodyStream); } return await this._parseResponseDefaultAsync(bodyStream); } async _processStreamingResponse(bodyStream) { const rl = createInterface({ input: bodyStream, crlfDelay: Infinity }); for await (const line of rl) { if (!line || line.trim().length === 0) { continue; } if (line.startsWith("{")) { const jsonStream = Readable.from([line]); let body = null; this.result = await this._defaultPipeline(_ => body = _).process(jsonStream); return body; } try { const unescaped = JSON.parse(line); await this._streamCallback(unescaped); } catch (err) { await this._streamCallback(line); } } if (!this.result) { throwError("InvalidOperationException", "No final result received in streaming response"); } return null; } } //# sourceMappingURL=RunConversationOperation.js.map