@inductiv/node-red-openai-api
Version:
Enhance your Node-RED projects with advanced AI capabilities.
199 lines (179 loc) • 5.15 kB
JavaScript
"use strict";
// This file keeps the ComparisonFilter contract honest.
// It checks that vector-store search forwards `in` and `nin` filters unchanged, and that the picker/example payloads stay aligned.
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const test = require("node:test");
function withMockedOpenAI(FakeOpenAI, callback) {
const openaiModule = require("openai");
const originalDescriptor = Object.getOwnPropertyDescriptor(openaiModule, "OpenAI");
Object.defineProperty(openaiModule, "OpenAI", {
value: FakeOpenAI,
configurable: true,
enumerable: true,
writable: true,
});
const run = async () => {
try {
return await callback();
} finally {
if (originalDescriptor) {
Object.defineProperty(openaiModule, "OpenAI", originalDescriptor);
}
}
};
return run();
}
const locale = JSON.parse(
fs.readFileSync(path.join(__dirname, "..", "locales", "en-US", "node.json"), "utf8")
);
const vectorStoreSearchExample = JSON.parse(
fs.readFileSync(path.join(__dirname, "..", "examples", "vector-store-search.json"), "utf8")
);
test("searchVectorStore forwards ComparisonFilter in/nin payloads unchanged to the OpenAI SDK", async () => {
const calls = [];
const requestPayload = {
vector_store_id: "vs_123",
query: "release alignment notes",
filters: {
type: "and",
filters: [
{
type: "in",
key: "team",
value: ["platform", "integrations"],
},
{
type: "nin",
key: "status",
value: ["archived", "draft"],
},
],
},
max_num_results: 5,
rewrite_query: true,
};
class FakeOpenAI {
constructor(clientParams) {
calls.push({ method: "ctor", clientParams });
this.vectorStores = {
search: async (vectorStoreId, body) => {
calls.push({ method: "vectorStores.search", vectorStoreId, body });
return {
data: [
{
file_id: "file_123",
filename: "release-notes.md",
attributes: {
team: "platform",
status: "published",
},
},
],
};
},
};
}
}
await withMockedOpenAI(FakeOpenAI, async () => {
const modulePath = require.resolve("../src/vector-stores/methods.js");
delete require.cache[modulePath];
const vectorStoreMethods = require("../src/vector-stores/methods.js");
const clientContext = {
clientParams: {
apiKey: "sk-test",
baseURL: "https://api.example.com/v1",
},
};
const response = await vectorStoreMethods.searchVectorStore.call(clientContext, {
payload: requestPayload,
});
assert.deepEqual(response, [
{
file_id: "file_123",
filename: "release-notes.md",
attributes: {
team: "platform",
status: "published",
},
},
]);
delete require.cache[modulePath];
});
const searchCalls = calls.filter((entry) => entry.method === "vectorStores.search");
assert.deepEqual(searchCalls, [
{
method: "vectorStores.search",
vectorStoreId: "vs_123",
body: {
query: "release alignment notes",
filters: {
type: "and",
filters: [
{
type: "in",
key: "team",
value: ["platform", "integrations"],
},
{
type: "nin",
key: "status",
value: ["archived", "draft"],
},
],
},
max_num_results: 5,
rewrite_query: true,
},
},
]);
});
test("vector-store picker exposes the search method", () => {
assert.equal(
locale.OpenaiApi.parameters.searchVectorStore,
"search vector store"
);
});
test("vector-store search example demonstrates in/nin ComparisonFilter usage", () => {
assert.ok(Array.isArray(vectorStoreSearchExample));
const openaiNode = vectorStoreSearchExample.find(
(entry) => entry.type === "OpenAI API"
);
const injectNode = vectorStoreSearchExample.find(
(entry) => entry.type === "inject" && entry.name === "Search Vector Store"
);
assert.ok(openaiNode);
assert.ok(injectNode);
assert.equal(openaiNode.method, "searchVectorStore");
assert.equal(
injectNode.props.find((prop) => prop.p === "ai.vector_store_id").v,
"vs_replace_me"
);
assert.equal(
injectNode.props.find((prop) => prop.p === "ai.query").v,
"release alignment notes"
);
assert.equal(
injectNode.props.find((prop) => prop.p === "ai.max_num_results").v,
"5"
);
assert.deepEqual(
JSON.parse(injectNode.props.find((prop) => prop.p === "ai.filters").v),
{
type: "and",
filters: [
{
type: "in",
key: "team",
value: ["platform", "integrations"],
},
{
type: "nin",
key: "status",
value: ["archived", "draft"],
},
],
}
);
});