@maximai/maxim-js
Version:
Maxim AI JS SDK. Visit https://getmaxim.ai for more info.
1,116 lines • 60.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Maxim = void 0;
const dataset_1 = require("./apis/dataset");
const folder_1 = require("./apis/folder");
const logs_1 = require("./apis/logs");
const prompt_1 = require("./apis/prompt");
const promptChain_1 = require("./apis/promptChain");
const inMemory_1 = require("./cache/inMemory");
const filterObjects_1 = require("./filterObjects");
const logger_1 = require("./logger/logger");
const utils_1 = require("./logger/utils");
const platform_1 = require("./platform");
const testRun_1 = require("./testRun/testRun");
const expiringKeyValueStore_1 = __importDefault(require("./utils/expiringKeyValueStore"));
var EntityType;
(function (EntityType) {
EntityType[EntityType["PROMPT"] = 0] = "PROMPT";
EntityType[EntityType["PROMPT_CHAIN"] = 1] = "PROMPT_CHAIN";
EntityType[EntityType["FOLDER"] = 2] = "FOLDER";
})(EntityType || (EntityType = {}));
/**
* Main class for the Maxim SDK that provides access to all platform features.
*
* The Maxim class is the primary entry point for interacting with the Maxim
* observability platform. It provides methods for prompt management, logging,
* dataset operations, and test run execution. The class handles authentication,
* caching, and API communication.
*
* @class Maxim
* @example
* import { Maxim } from '@maximai/maxim-js';
*
* // Basic initialization
* const maxim = new Maxim({
* apiKey: 'your-api-key'
* });
*
* @example
* // Full configuration
* const maxim = new Maxim({
* apiKey: 'your-api-key',
* baseUrl: 'https://app.getmaxim.ai',
* promptManagement: true,
* debug: true,
* cache: new CustomCacheImplementation()
* });
*
* @example
* // Using prompt management
* const maxim = new Maxim({
* apiKey: 'your-api-key',
* promptManagement: true
* });
*
* // Get a prompt with deployment rules
* const rule = new QueryBuilder()
* .deploymentVar('environment', 'production')
* .tag('version', 'v2.0')
* .build();
*
* const prompt = await maxim.getPrompt('prompt-id', rule);
* if (prompt) {
* const response = await prompt.run('Hello world');
* console.log(response.choices[0].message.content);
* }
*
* @example
* // Creating and running test runs
* const testResult = await maxim
* .createTestRun('sample-test-run', 'workspace-id')
* .withDataStructure({
* input: 'INPUT',
* expectedOutput: 'EXPECTED_OUTPUT'
* })
* .withData('dataset-id')
* .withEvaluators('bias', 'toxicity')
* .yieldsOutput(async (data) => {
* const response = await callYourModel(data.input);
* return { data: response };
* })
* .run();
*
* @example
* // Logging with Maxim
* const logger = await maxim.logger({ id: 'my-app' });
* const session = logger.session({ id: 'session-1', name: 'User session' });
* const trace = session.trace({ id: 'trace-1', name: 'Query Processing', sessionId: 'session-1' });
*
* // ... Log other operations
*
* trace.end();
*
* // finally, before app shutdown
* await maxim.cleanup();
*/
class Maxim {
/**
* Creates a new Maxim SDK instance.
*
* @param config - Configuration object for the SDK
* @throws {Error} When the API key is not provided
* @important **CRITICAL**: Always call `cleanup()` before your application
* exits. Failure to do so may result in memory leaks, unflushed data, or
* hanging processes. This is especially important in production environments
* and long-running applications.
* @example
* const maxim = new Maxim({
* apiKey: process.env.MAXIM_API_KEY,
* promptManagement: true,
* debug: process.env.NODE_ENV === 'development'
* });
*
* @example
* // With custom cache
* import { RedisCacheImplementation } from './custom-cache';
*
* const maxim = new Maxim({
* apiKey: 'your-api-key',
* cache: new RedisCacheImplementation({
* host: 'localhost',
* port: 6379
* })
* });
*
* // Always remember to cleanup before exit
* process.on('SIGINT', async () => {
* await maxim.cleanup();
* process.exit(0);
* });
*/
constructor(config) {
this.isPromptManagementEnabled = false;
this.loggers = new Map();
this.promptVersionByNumberCache = new expiringKeyValueStore_1.default();
if (!config.apiKey) {
throw new Error("[Maxim-SDK] API key is required");
}
// Check if an instance with the same API key already exists
if (globalThis.__maxim__sdk__instances__ && globalThis.__maxim__sdk__instances__.get(config.apiKey)) {
console.warn("[Maxim-SDK] You have initialized multiple instances of Maxim with the same API key.");
}
this.baseUrl = config.baseUrl || "https://app.getmaxim.ai";
this.apiKey = config.apiKey;
this._raiseExceptions = config.raiseExceptions || false;
this.isDebug = config.debug || false;
this.APIService = {
prompt: new prompt_1.MaximPromptAPI(this.baseUrl, this.apiKey, this.isDebug),
promptChain: new promptChain_1.MaximPromptChainAPI(this.baseUrl, this.apiKey, this.isDebug),
folder: new folder_1.MaximFolderAPI(this.baseUrl, this.apiKey, this.isDebug),
dataset: new dataset_1.MaximDatasetAPI(this.baseUrl, this.apiKey, this.isDebug),
logs: new logs_1.MaximLogsAPI(this.baseUrl, this.apiKey, this.isDebug),
};
this.cache = config.cache || new inMemory_1.MaximInMemoryCache();
if (config.promptManagement) {
this.isPromptManagementEnabled = true;
this.sync = this.syncEntities();
this.intervalHandle = platform_1.platform.timers.setInterval(() => {
this.syncEntities();
}, 1000 * 60);
// Call unref() to tell Node.js that this interval should not keep the process alive
platform_1.platform.timers.maybeUnref(this.intervalHandle);
}
// Initialize or update the global instances array
if (!globalThis.__maxim__sdk__instances__) {
globalThis.__maxim__sdk__instances__ = new Map();
}
globalThis.__maxim__sdk__instances__.set(this.apiKey, this);
}
// We will always bootstrap using REST call
// Updates will be sent using realtime server
async syncEntities() {
try {
return new Promise((resolve, reject) => {
Promise.all([this.syncPrompts(), this.syncFolders(), this.syncPromptChains()])
.then(() => {
resolve();
})
.catch((err) => {
console.error(`[Maxim-SDK] ${err}`);
resolve();
});
});
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while syncing entities: ${err instanceof Error ? err.message : err}`);
}
}
}
async syncPrompts() {
try {
await this.APIService.prompt.getPrompts().then(async (prompts) => {
if (this.isDebug) {
console.log(`[Maxim-SDK] Syncing ${prompts.length} prompts`);
}
await Promise.all(prompts.map(async (prompt) => {
try {
await this.cache.set(this.getCacheKey(EntityType.PROMPT, prompt.promptId), JSON.stringify(prompt));
}
catch (err) {
console.error(err);
}
}));
});
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while syncing prompts: ${err instanceof Error ? err.message : err}`);
}
}
}
async syncPromptChains() {
try {
await this.APIService.promptChain.getPromptChains().then(async (promptChains) => {
if (this.isDebug) {
console.log(`[Maxim-SDK] Syncing ${promptChains.length} prompt chains`);
}
await Promise.all(promptChains.map(async (promptChain) => {
try {
await this.cache.set(this.getCacheKey(EntityType.PROMPT_CHAIN, promptChain.promptChainId), JSON.stringify(promptChain));
}
catch (err) {
console.error(err);
}
}));
});
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while syncing prompt chains: ${err instanceof Error ? err.message : err}`);
}
}
}
async syncFolders() {
try {
await this.APIService.folder.getFolders().then(async (folders) => {
if (this.isDebug) {
console.log(`[Maxim-SDK] Syncing ${folders.length} folders`);
}
await Promise.all(folders.map(async (folder) => {
try {
await this.cache.set(this.getCacheKey(EntityType.FOLDER, folder.id), JSON.stringify(folder));
}
catch (err) {
console.error(err);
}
}));
});
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while syncing folders: ${err instanceof Error ? err.message : err}`);
}
}
}
async getPromptFromCache(key) {
try {
let data = await this.cache.get(key);
if (!data) {
return null;
}
return JSON.parse(data);
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompt from cache: ${err instanceof Error ? err.message : err}`);
return null;
}
}
}
async getAllPromptsFromCache() {
try {
let keys = await this.cache.getAllKeys();
if (!keys) {
return null;
}
// Fetching all prompts
let data = await Promise.all(keys.filter((key) => key.startsWith("prompt:")).map((key) => this.cache.get(key)));
return data.filter((d) => d !== null).map((d) => JSON.parse(d));
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching all prompts from cache: ${err instanceof Error ? err.message : err}`);
return null;
}
}
}
async getPromptChainFromCache(key) {
try {
let data = await this.cache.get(key);
if (!data) {
return null;
}
return JSON.parse(data);
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompt chain from cache: ${err instanceof Error ? err.message : err}`);
return null;
}
}
}
async getAllPromptChainsFromCache() {
try {
let keys = await this.cache.getAllKeys();
if (!keys) {
return null;
}
// Fetching all prompts
let data = await Promise.all(keys.filter((key) => key.startsWith("promptChain:")).map((key) => this.cache.get(key)));
return data.filter((d) => d !== null).map((d) => JSON.parse(d));
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching all prompt chains from cache: ${err instanceof Error ? err.message : err}`);
return null;
}
}
}
async getFolderFromCache(key) {
try {
let data = await this.cache.get(key);
if (!data) {
return null;
}
return JSON.parse(data);
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching folder from cache: ${err instanceof Error ? err.message : err}`);
return null;
}
}
}
async getAllFoldersFromCache() {
try {
let keys = await this.cache.getAllKeys();
if (!keys) {
return null;
}
// Fetching all prompts
let data = await Promise.all(keys.filter((key) => key.startsWith("folder:")).map((key) => this.cache.get(key)));
return data.filter((d) => d !== null).map((d) => JSON.parse(d));
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching all folders from cache: ${err instanceof Error ? err.message : err}`);
return null;
}
}
}
getCacheKey(entity, id) {
switch (entity) {
case EntityType.PROMPT:
return `prompt:${id}`;
case EntityType.PROMPT_CHAIN:
return `promptChain:${id}`;
case EntityType.FOLDER:
return `folder:${id}`;
}
}
getPromptVersionForRule(promptVersionAndRules, rule) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
const sdk = this;
try {
if (rule) {
let incomingQuery = {
query: rule.query,
operator: rule.operator,
exactMatch: rule.exactMatch,
};
const objects = [];
Object.keys(promptVersionAndRules.rules).forEach((versionId) => {
const versionRules = promptVersionAndRules.rules[versionId];
versionRules.forEach((versionRule) => {
var _a;
if (!versionRule.rules.query) {
return;
}
// Checking for scope and type of scope and filtering candidates
if (rule.scopes) {
Object.keys(rule.scopes).forEach((key) => {
switch (key) {
case "folder":
break;
default:
throw new Error("Invalid scope added");
}
});
}
const version = promptVersionAndRules === null || promptVersionAndRules === void 0 ? void 0 : promptVersionAndRules.versions.find((v) => v.id === versionId);
const query = versionRule.rules.query;
if (!version)
return;
// Here we will attach tags to that query
if ((_a = version.config) === null || _a === void 0 ? void 0 : _a.tags) {
const parsedIncomingQuery = (0, filterObjects_1.parseIncomingQuery)(incomingQuery.query);
const tags = version.config.tags;
// Generating QueryType from key value pair in tags
Object.keys(tags)
.filter((key) => tags[key] !== undefined)
.filter((key) => parsedIncomingQuery.map((incomingQueryRule) => incomingQueryRule.field).includes(key))
.forEach((key) => {
query.rules.push({ field: key, operator: "=", value: tags[key] });
});
}
objects.push({
query,
id: versionId,
});
});
});
const deployedVersionObject = (0, filterObjects_1.findBestMatch)(objects, incomingQuery);
if (deployedVersionObject) {
const deployedVersion = promptVersionAndRules === null || promptVersionAndRules === void 0 ? void 0 : promptVersionAndRules.versions.find((v) => v.id === deployedVersionObject.id);
let prompt;
prompt = {
promptId: deployedVersion.promptId,
versionId: deployedVersion.id,
version: deployedVersion.version,
messages: (_a = deployedVersion.config) === null || _a === void 0 ? void 0 : _a.messages,
modelParameters: ((_b = deployedVersion.config) === null || _b === void 0 ? void 0 : _b.modelParameters) || {},
model: ((_c = deployedVersion.config) === null || _c === void 0 ? void 0 : _c.model) || "",
deploymentId: (_d = deployedVersion.config) === null || _d === void 0 ? void 0 : _d.deploymentId,
provider: ((_e = deployedVersion.config) === null || _e === void 0 ? void 0 : _e.provider) || "",
tags: ((_f = deployedVersion.config) === null || _f === void 0 ? void 0 : _f.tags) || {},
run: async function (input, options) {
if (!deployedVersion) {
throw new Error("[Maxim-SDK] Deployed version missing while attempting to run prompt");
}
return executePromptWithLogging(this.parent, this.generationConfig, deployedVersion, options, () => sdk.APIService.prompt.runPromptVersion(deployedVersion.id, input, options));
},
withLogger: function (parent, generationConfig) {
const newPrompt = {
...this,
parent,
generationConfig,
};
return newPrompt;
},
};
return prompt;
}
}
else {
// Checking version rules with rule being undefined
for (const versionId in promptVersionAndRules.rules) {
const versionRules = promptVersionAndRules.rules[versionId];
let isMatch = false;
for (const rule of versionRules) {
if (rule.rules.query === undefined || ((_g = rule.rules.query) === null || _g === void 0 ? void 0 : _g.rules.length) === 0) {
isMatch = true;
break;
}
}
if (isMatch) {
const deployedVersion = promptVersionAndRules.versions.find((v) => v.id === versionId);
let prompt;
prompt = {
promptId: deployedVersion.promptId,
versionId: deployedVersion.id,
version: deployedVersion.version,
messages: (_h = deployedVersion.config) === null || _h === void 0 ? void 0 : _h.messages,
modelParameters: ((_j = deployedVersion.config) === null || _j === void 0 ? void 0 : _j.modelParameters) || {},
model: ((_k = deployedVersion.config) === null || _k === void 0 ? void 0 : _k.model) || "",
deploymentId: (_l = deployedVersion.config) === null || _l === void 0 ? void 0 : _l.deploymentId,
provider: ((_m = deployedVersion.config) === null || _m === void 0 ? void 0 : _m.provider) || "",
tags: ((_o = deployedVersion.config) === null || _o === void 0 ? void 0 : _o.tags) || {},
run: async function (input, options) {
if (!deployedVersion) {
throw new Error("[Maxim-SDK] Deployed version missing while attempting to run prompt");
}
return executePromptWithLogging(this.parent, this.generationConfig, deployedVersion, options, () => sdk.APIService.prompt.runPromptVersion(deployedVersion.id, input, options));
},
withLogger: function (parent, generationConfig) {
const newPrompt = {
...this,
parent,
generationConfig,
};
return newPrompt;
},
};
return prompt;
}
}
}
if (promptVersionAndRules.fallbackVersion) {
let prompt;
prompt = {
promptId: promptVersionAndRules.fallbackVersion.promptId,
versionId: promptVersionAndRules.fallbackVersion.id,
version: promptVersionAndRules.fallbackVersion.version,
...promptVersionAndRules.fallbackVersion.config,
messages: ((_p = promptVersionAndRules.fallbackVersion.config) === null || _p === void 0 ? void 0 : _p.messages) || [],
modelParameters: ((_q = promptVersionAndRules.fallbackVersion.config) === null || _q === void 0 ? void 0 : _q.modelParameters) || {},
model: ((_r = promptVersionAndRules.fallbackVersion.config) === null || _r === void 0 ? void 0 : _r.model) || "",
provider: ((_s = promptVersionAndRules.fallbackVersion.config) === null || _s === void 0 ? void 0 : _s.provider) || "",
tags: ((_t = promptVersionAndRules.fallbackVersion.config) === null || _t === void 0 ? void 0 : _t.tags) || {},
run: async function (input, options) {
var _a;
if (!((_a = promptVersionAndRules.fallbackVersion) === null || _a === void 0 ? void 0 : _a.id)) {
throw new Error("[Maxim-SDK] Deployed fallback version missing while attempting to run prompt");
}
return executePromptWithLogging(this.parent, this.generationConfig, promptVersionAndRules.fallbackVersion, options, () => sdk.APIService.prompt.runPromptVersion(promptVersionAndRules.fallbackVersion.id, input, options));
},
withLogger: function (parent, generationConfig) {
const newPrompt = {
...this,
parent,
generationConfig,
};
return newPrompt;
},
};
return prompt;
}
return undefined;
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompt version for rule: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
getPromptChainVersionForRule(promptChainVersionAndRules, rule) {
var _a, _b, _c;
try {
if (rule) {
let incomingQuery = {
query: rule.query,
operator: rule.operator,
exactMatch: rule.exactMatch,
};
const objects = [];
Object.keys(promptChainVersionAndRules.rules).forEach((versionId) => {
const versionRules = promptChainVersionAndRules.rules[versionId];
versionRules.forEach((versionRule) => {
if (!versionRule.rules.query) {
return;
}
// Checking for scope and type of scope and filtering candidates
if (rule.scopes) {
Object.keys(rule.scopes).forEach((key) => {
switch (key) {
case "folder":
break;
default:
throw new Error("Invalid scope added");
}
});
}
const version = promptChainVersionAndRules === null || promptChainVersionAndRules === void 0 ? void 0 : promptChainVersionAndRules.versions.find((v) => v.id === versionId);
const query = versionRule.rules.query;
if (!version)
return;
// Here we will attach tags to that query
objects.push({
query,
id: versionId,
});
});
});
const deployedVersionObject = (0, filterObjects_1.findBestMatch)(objects, incomingQuery);
if (deployedVersionObject) {
const deployedVersion = promptChainVersionAndRules === null || promptChainVersionAndRules === void 0 ? void 0 : promptChainVersionAndRules.versions.find((v) => v.id === deployedVersionObject.id);
return {
promptChainId: deployedVersion.promptChainId,
versionId: deployedVersion.id,
version: deployedVersion.version,
nodes: (_a = deployedVersion.config) === null || _a === void 0 ? void 0 : _a.nodes.filter((n) => "prompt" in n),
run: (input, options) => {
if (!(deployedVersion === null || deployedVersion === void 0 ? void 0 : deployedVersion.id)) {
throw new Error("[Maxim-SDK] Deployed version missing while attempting to run prompt chain");
}
return this.APIService.promptChain.runPromptChainVersion(deployedVersion.id, input, options);
},
};
}
}
else {
// Checking version rules with rule being undefined
for (const versionId in promptChainVersionAndRules.rules) {
const versionRules = promptChainVersionAndRules.rules[versionId];
let isMatch = false;
for (const rule of versionRules) {
if (rule.rules.query === undefined || ((_b = rule.rules.query) === null || _b === void 0 ? void 0 : _b.rules.length) === 0) {
isMatch = true;
break;
}
}
if (isMatch) {
const deployedVersion = promptChainVersionAndRules.versions.find((v) => v.id === versionId);
return {
promptChainId: deployedVersion.promptChainId,
versionId: deployedVersion.id,
version: deployedVersion.version,
nodes: (_c = deployedVersion.config) === null || _c === void 0 ? void 0 : _c.nodes.filter((n) => "prompt" in n),
run: (input, options) => {
if (!(deployedVersion === null || deployedVersion === void 0 ? void 0 : deployedVersion.id)) {
throw new Error("[Maxim-SDK] Deployed version missing while attempting to run prompt chain");
}
return this.APIService.promptChain.runPromptChainVersion(deployedVersion.id, input, options);
},
};
}
}
}
if (promptChainVersionAndRules.fallbackVersion) {
return {
promptChainId: promptChainVersionAndRules.fallbackVersion.promptChainId,
versionId: promptChainVersionAndRules.fallbackVersion.id,
version: promptChainVersionAndRules.fallbackVersion.version,
nodes: promptChainVersionAndRules.fallbackVersion.config
? promptChainVersionAndRules.fallbackVersion.config.nodes.filter((n) => "prompt" in n)
: [],
run: (input, options) => {
var _a;
if (!((_a = promptChainVersionAndRules.fallbackVersion) === null || _a === void 0 ? void 0 : _a.id)) {
throw new Error("[Maxim-SDK] Deployed fallback version missing while attempting to run prompt chain");
}
return this.APIService.promptChain.runPromptChainVersion(promptChainVersionAndRules.fallbackVersion.id, input, options);
},
};
}
return undefined;
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompt chain version for rule: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
getFoldersForRule(folders, rule) {
try {
let incomingQuery = {
query: rule.query,
operator: rule.operator,
exactMatch: rule.exactMatch,
};
const objects = [];
folders.forEach((folder) => {
const query = {
combinator: "AND",
not: false,
rules: [],
};
if (!folder.tags) {
return;
}
const parsedIncomingQuery = (0, filterObjects_1.parseIncomingQuery)(incomingQuery.query);
const tags = folder.tags;
Object.keys(tags)
.filter((key) => tags[key] !== undefined)
.filter((key) => parsedIncomingQuery.map((rule) => rule.field).includes(key))
.forEach((key) => {
query.rules.push({ field: key, operator: "=", value: tags[key] });
});
if (query.rules.length === 0) {
return;
}
objects.push({
query,
id: folder.id,
});
});
const folderObjects = (0, filterObjects_1.findAllMatches)(objects, incomingQuery);
const ids = folderObjects.map((fo) => fo.id);
return folders.filter((f) => ids.includes(f.id));
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching folders for rule: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
/**
* Retrieves a specific prompt by ID that matches the given query rule.
*
* This method fetches a prompt from the Maxim platform based on deployment rules
* and query criteria. It supports versioning and rule-based prompt selection.
*
* @async
* @param promptId - The unique identifier of the prompt to fetch
* @param rule - Query rule defining deployment variables, tags, and matching criteria
* @returns The matching prompt with run capabilities, or undefined if not found
* @throws {Error} When prompt management is not enabled
* @throws {Error} When no active deployments found for the prompt matching the query rule
* @example
* import { QueryBuilder } from '@maximai/maxim-js';
*
* const rule = new QueryBuilder()
* .deploymentVar('environment', 'production')
* .tag('version', 'v2.0')
* .build();
*
* const prompt = await maxim.getPrompt('user-greeting-prompt-id', rule);
* if (prompt) {
* const response = await prompt.run('Hello!', {
* variables: { userName: 'John' },
* imageUrls: []
* });
* console.log(response.choices[0].message.content);
* }
*
* @example
* // Using folder-scoped queries
* const rule = new QueryBuilder()
* .folder('customer-service-folder')
* .deploymentVar('language', 'en')
* .build();
*
* const prompt = await maxim.getPrompt('support-template', rule);
*/
async getPrompt(promptId, rule) {
var _a, _b, _c, _d, _e, _f;
const sdk = this;
try {
if (!this.isPromptManagementEnabled) {
throw new Error("Prompt Management feature is not enabled. Please enable it in the configuration.");
}
await this.sync;
// Short-circuit: if only condition is promptVersionNumber, fetch exact version with 60s TTL
const parsed = (0, filterObjects_1.parseIncomingQuery)(rule.query);
if (parsed.length === 1 && parsed[0].field === "promptVersionNumber" && parsed[0].operator === "=") {
const num = Number(parsed[0].value);
if (isNaN(num)) {
throw new Error("Invalid promptVersionNumber value");
}
const cacheKey = `pvnum:${promptId}:${num}`;
const cached = this.promptVersionByNumberCache.get(cacheKey);
if (cached) {
return cached;
}
const versionAndRules = await this.APIService.prompt.getPrompt(promptId, num);
if (!versionAndRules || versionAndRules.versions.length === 0) {
throw new Error(`No active deployments found for Prompt ${promptId}`);
}
const deployedVersion = versionAndRules.versions.find((v) => v.version === num);
if (!deployedVersion) {
throw new Error(`No version ${num} found for Prompt ${promptId}`);
}
let prompt;
prompt = {
promptId: deployedVersion.promptId,
versionId: deployedVersion.id,
version: deployedVersion.version,
messages: ((_a = deployedVersion.config) === null || _a === void 0 ? void 0 : _a.messages) || [],
modelParameters: ((_b = deployedVersion.config) === null || _b === void 0 ? void 0 : _b.modelParameters) || {},
model: ((_c = deployedVersion.config) === null || _c === void 0 ? void 0 : _c.model) || "",
deploymentId: (_d = deployedVersion.config) === null || _d === void 0 ? void 0 : _d.deploymentId,
provider: ((_e = deployedVersion.config) === null || _e === void 0 ? void 0 : _e.provider) || "",
tags: ((_f = deployedVersion.config) === null || _f === void 0 ? void 0 : _f.tags) || {},
run: async function (input, options) {
return executePromptWithLogging(this.parent, this.generationConfig, deployedVersion, options, () => sdk.APIService.prompt.runPromptVersion(deployedVersion.id, input, options));
},
withLogger: function (parent, generationConfig) {
const newPrompt = {
...this,
parent,
generationConfig,
};
return newPrompt;
},
};
this.promptVersionByNumberCache.set(cacheKey, prompt, 60);
return prompt;
}
const key = this.getCacheKey(EntityType.PROMPT, promptId);
// check if prompt is present in cache
let versionAndRules = await this.getPromptFromCache(key);
// If not present in cache, we make an API call and set in cache
if (versionAndRules === null) {
versionAndRules = await this.APIService.prompt.getPrompt(promptId);
if (versionAndRules.versions.length === 0) {
throw new Error(`No active deployments found for Prompt ${promptId}`);
}
await this.cache.set(promptId, JSON.stringify(versionAndRules));
}
// Neither present in cache nor received via API call
if (!versionAndRules) {
throw new Error(`No active deployments found for Prompt ${promptId}`);
}
const prompt = this.getPromptVersionForRule(versionAndRules, rule);
if (!prompt) {
throw new Error(`No active deployments found for Prompt ${promptId}`);
}
return prompt;
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompt: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
/**
* Retrieves all prompts that match the given query rule.
*
* This method fetches multiple prompts from the Maxim platform based on
* deployment rules and query criteria. Useful for getting all prompts
* within a specific folder or matching certain deployment variables.
*
* @async
* @param rule - Query rule defining deployment variables, tags, and matching criteria
* @returns Array of matching prompts with run capabilities, or undefined if none found
* @throws {Error} When prompt management is not enabled
* @throws {Error} When no active deployments found for any prompt matching the query rule
* @example
* import { QueryBuilder } from '@maximai/maxim-js';
*
* // Get all production prompts in a specific folder
* const rule = new QueryBuilder()
* .folder('customer-support')
* .deploymentVar('environment', 'production')
* .build();
*
* const prompts = await maxim.getPrompts(rule);
* if (prompts) {
* for (const prompt of prompts) {
* console.log(`Prompt: ${prompt.promptId}, Version: ${prompt.version}`);
* }
* }
*
* @example
* // Get all prompts with specific tags
* const rule = new QueryBuilder()
* .tag('category', 'greeting')
* .tag('language', 'english')
* .and()
* .build();
*
* const greetingPrompts = await maxim.getPrompts(rule);
*/
async getPrompts(rule) {
try {
if (!this.isPromptManagementEnabled) {
throw new Error("Prompt Management feature is not enabled. Please enable it in the configuration.");
}
await this.sync;
let versionAndRules = await this.getAllPromptsFromCache();
if (versionAndRules === null || versionAndRules.length === 0) {
// We will try to get all prompts from server (if something has gone wrong with initialization)
await this.syncEntities();
versionAndRules = await this.getAllPromptsFromCache();
}
if (!versionAndRules) {
throw new Error(`No active deployments found for any prompt`);
}
let prompts = versionAndRules
.filter((v) => {
if (Object.keys(rule.scopes).length === 0) {
return true;
}
if (rule.scopes["folder"]) {
return v.folderId === rule.scopes["folder"];
}
return true;
})
.map((v) => this.getPromptVersionForRule(v, rule))
.filter((p) => p !== undefined);
if (prompts.length === 0) {
throw new Error(`No active deployments found for any prompt`);
}
return prompts;
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompts: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
/**
* Retrieves a specific prompt chain by ID that matches the given query rule.
*
* This method fetches a prompt chain from the Maxim platform based on deployment rules
* and query criteria. It supports versioning and rule-based prompt chain selection.
* Prompt chains allow you to orchestrate multiple prompts in sequence with conditional logic.
*
* @async
* @param promptChainId - The unique identifier of the prompt chain to fetch
* @param rule - Query rule defining deployment variables, tags, and matching criteria
* @returns The matching prompt chain with run capabilities, or undefined if not found
* @throws {Error} When prompt management is not enabled
* @throws {Error} When no active deployments found for the prompt chain matching the query rule
* @example
* import { QueryBuilder } from '@maximai/maxim-js';
*
* const rule = new QueryBuilder()
* .deploymentVar('environment', 'production')
* .tag('version', 'v2.0')
* .build();
*
* const promptChain = await maxim.getPromptChain('user-onboarding-chain-id', rule);
* if (promptChain) {
* const response = await promptChain.run('New user registration', {
* variables: { userName: 'John', userType: 'premium' }
* });
* console.log(response.finalOutput);
* }
*
* @example
* // Using folder-scoped queries
* const rule = new QueryBuilder()
* .folder('customer-onboarding-folder')
* .deploymentVar('language', 'en')
* .build();
*
* const promptChain = await maxim.getPromptChain('welcome-sequence', rule);
*/
async getPromptChain(promptChainId, rule) {
try {
if (!this.isPromptManagementEnabled) {
throw new Error("Prompt Management feature is not enabled. Please enable it in the configuration.");
}
await this.sync;
const key = this.getCacheKey(EntityType.PROMPT_CHAIN, promptChainId);
let versionAndRules = await this.getPromptChainFromCache(key);
if (versionAndRules === null) {
versionAndRules = await this.APIService.promptChain.getPromptChain(promptChainId);
if (versionAndRules.versions.length === 0) {
throw new Error(`No active deployments found for Prompt Chain ${promptChainId}`);
}
await this.cache.set(promptChainId, JSON.stringify(versionAndRules));
}
if (!versionAndRules) {
throw new Error(`No active deployments found for Prompt Chain ${promptChainId}`);
}
const promptChain = this.getPromptChainVersionForRule(versionAndRules, rule);
if (!promptChain) {
throw new Error(`No active deployments found for Prompt Chain ${promptChainId}`);
}
return promptChain;
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompt chain: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
/**
* Retrieves all prompt chains that match the given query rule.
*
* This method fetches multiple prompt chains from the Maxim platform based on
* deployment rules and query criteria. Useful for getting all prompt chains
* within a specific folder or matching certain deployment variables.
*
* @async
* @param rule - Query rule defining deployment variables, tags, and matching criteria
* @returns Array of matching prompt chains with run capabilities, or undefined if none found
* @throws {Error} When prompt management is not enabled
* @throws {Error} When no active deployments found for any prompt chain matching the query rule
* @example
* import { QueryBuilder } from '@maximai/maxim-js';
*
* // Get all production prompt chains in a specific folder
* const rule = new QueryBuilder()
* .folder('customer-support')
* .deploymentVar('environment', 'production')
* .build();
*
* const promptChains = await maxim.getPromptChains(rule);
* if (promptChains) {
* for (const promptChain of promptChains) {
* console.log(`Prompt Chain: ${promptChain.promptChainId}, Version: ${promptChain.version}`);
* }
* }
*
* @example
* // Get all prompt chains with specific tags
* const rule = new QueryBuilder()
* .tag('category', 'workflow')
* .tag('complexity', 'advanced')
* .and()
* .build();
*
* const workflowChains = await maxim.getPromptChains(rule);
*/
async getPromptChains(rule) {
try {
if (!this.isPromptManagementEnabled) {
throw new Error("Prompt Management feature is not enabled. Please enable it in the configuration.");
}
await this.sync;
let versionAndRules = await this.getAllPromptChainsFromCache();
if (versionAndRules === null || versionAndRules.length === 0) {
// We will try to get all prompts from server (if something has gone wrong with initialization)
await this.syncEntities();
versionAndRules = await this.getAllPromptChainsFromCache();
}
if (!versionAndRules) {
throw new Error(`No active deployments found for any prompt chain`);
}
let promptChains = versionAndRules
.filter((v) => {
if (Object.keys(rule.scopes).length === 0) {
return true;
}
if (rule.scopes["folder"]) {
return v.folderId === rule.scopes["folder"];
}
return true;
})
.map((v) => this.getPromptChainVersionForRule(v, rule))
.filter((p) => p !== undefined);
if (promptChains.length === 0) {
throw new Error(`No active deployments found for any prompt chain`);
}
return promptChains;
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching prompt chains: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
/**
* This method is used to get a folder by id
* @async
* @param folderId - Folder id to fetch
* @returns a single folder
* @throws {Error} If no folder found with id
* @example
* const folder = await maxim.getFolderById("folderId");
*/
async getFolderById(folderId) {
try {
if (!this.isPromptManagementEnabled) {
throw new Error("Prompt Management feature is not enabled. Please enable it in the configuration.");
}
await this.sync;
const key = this.getCacheKey(EntityType.FOLDER, folderId);
let folder = await this.getFolderFromCache(key);
if (folder === null) {
folder = await this.APIService.folder.getFolder(folderId);
if (!folder) {
throw new Error(`No folder found with id ${folderId}`);
}
await this.cache.set(key, JSON.stringify(folder));
}
return folder;
}
catch (err) {
if (this._raiseExceptions) {
throw err;
}
else {
console.error(`[Maxim-SDK] Error while fetching folder by id: ${err instanceof Error ? err.message : err}`);
return undefined;
}
}
}
/**
* This method is used to get all folders that match the query rule
* @async