@daitanjs/intelligence
Version:
A modular library for advanced LLM orchestration, stateful RAG, multi-step agentic workflows, and tool use, built on LangChain.js.
1,374 lines (1,354 loc) • 283 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/intelligence/src/index.js
var src_exports = {};
__export(src_exports, {
BaseAgent: () => BaseAgent,
BaseTool: () => BaseTool,
ChoreographerAgent: () => ChoreographerAgent,
CoachAgent: () => CoachAgent,
DaitanConfigManagerClass: () => import_config20.DaitanConfigManagerClass,
DaitanLangGraph: () => DaitanLangGraph,
DaitanOrchestrator: () => DaitanOrchestrator,
InMemoryChatMessageHistoryStore: () => InMemoryChatMessageHistoryStore,
LLMService: () => LLMService,
OpeningPhraseAgent: () => OpeningPhraseAgent,
ParticipantAgent: () => ParticipantAgent,
askWithRetrieval: () => askWithRetrieval,
checkChromaConnection: () => checkChromaConnection,
checkOllamaStatus: () => checkOllamaStatus,
clearCache: () => clearCache,
countTokens: () => countTokens,
countTokensForMessages: () => countTokensForMessages,
createDaitanTool: () => createDaitanTool,
createGraphRunner: () => createGraphRunner,
createRagChatInstance: () => createRagChatInstance,
estimateLlmCost: () => estimateLlmCost,
generateCacheKey: () => generateCacheKey,
generateEmbedding: () => import_embeddings.generateEmbedding,
generateIntelligence: () => generateIntelligence,
getCache: () => getCache,
getConfigManager: () => import_config20.getConfigManager,
getDaitanPlatformTools: () => getDaitanPlatformTools,
getDefaultTools: () => getDefaultTools,
getVectorStore: () => getVectorStore,
initializeConfigManager: () => import_config20.initializeConfigManager,
loadAndEmbedFile: () => loadAndEmbedFile,
printStoreStats: () => printStoreStats,
runAutomatedResearchWorkflow: () => runAutomatedResearchWorkflow,
runDeepResearchAgent: () => runDeepResearchAgent,
runGraphAgent: () => runGraphAgent,
runToolCallingAgent: () => runToolCallingAgent,
searchAcademic: () => searchAcademic,
searchAndUnderstand: () => searchAndUnderstand,
searchGeneralWeb: () => searchGeneralWeb,
searchNews: () => searchNews,
translate: () => translate,
vectorStoreCollectionExists: () => vectorStoreCollectionExists
});
module.exports = __toCommonJS(src_exports);
var import_development50 = require("@daitanjs/development");
// src/intelligence/src/orchestration/daitanOrchestrator.js
var import_development47 = require("@daitanjs/development");
var import_config18 = require("@daitanjs/config");
// src/intelligence/src/intelligence/core/llmOrchestrator.js
var import_openai = require("@langchain/openai");
var import_anthropic = require("@langchain/anthropic");
var import_groq = require("@langchain/groq");
var import_output_parsers = require("@langchain/core/output_parsers");
var import_config = require("@daitanjs/config");
var import_error = require("@daitanjs/error");
// src/intelligence/src/intelligence/core/promptBuilder.js
var import_messages = require("@langchain/core/messages");
var import_development = require("@daitanjs/development");
var promptBuilderLogger = (0, import_development.getLogger)("daitan-prompt-builder");
function convertToLangChainMessages(messages) {
if (!Array.isArray(messages)) {
return [];
}
return messages.reduce((acc, msg) => {
if (msg instanceof import_messages.BaseMessage) {
acc.push(msg);
} else if (typeof msg === "object" && msg !== null && typeof msg.role === "string" && (typeof msg.content === "string" || Array.isArray(msg.content) || typeof msg.content === "object")) {
const role = msg.role.toLowerCase();
try {
if (role === "system")
acc.push(new import_messages.SystemMessage({ content: msg.content }));
else if (role === "user" || role === "human")
acc.push(new import_messages.HumanMessage({ content: msg.content }));
else if (role === "assistant" || role === "ai")
acc.push(new import_messages.AIMessage({ content: msg.content }));
else {
promptBuilderLogger.warn(
`Unknown message role "${msg.role}". Treating as human.`
);
acc.push(new import_messages.HumanMessage({ content: msg.content }));
}
} catch (e) {
promptBuilderLogger.error(
"Failed to create LangChain message from object.",
{ messageObject: msg, error: e.message }
);
}
}
return acc;
}, []);
}
var buildLlmMessages = (prompt = {}) => {
const systemConfig = prompt.system || {};
const userContent = prompt.user;
const fewShotExamples = prompt.shots || [];
const systemInstructionParts = [
systemConfig.persona,
systemConfig.whoYouAre,
// Legacy support
systemConfig.task,
systemConfig.whatYouDo,
// Legacy support
systemConfig.guidelines,
systemConfig.vitals,
systemConfig.scoring,
systemConfig.writingStyle,
systemConfig.outputFormat,
systemConfig.outputFormatDescription,
// Legacy support
systemConfig.promptingTips,
systemConfig.reiteration
];
const systemInstructionContent = systemInstructionParts.filter(Boolean).join("\n\n");
let messages = [];
if (systemInstructionContent) {
messages.push({ role: "system", content: systemInstructionContent });
}
if (Array.isArray(fewShotExamples) && fewShotExamples.length > 0) {
messages.push(
...fewShotExamples.filter(
(s) => s && typeof s.role === "string" && (typeof s.content === "string" || Array.isArray(s.content) || typeof s.content === "object")
)
);
}
if (userContent && (typeof userContent === "string" || typeof userContent === "object")) {
messages.push({ role: "user", content: userContent });
}
return convertToLangChainMessages(messages);
};
// src/intelligence/src/intelligence/core/expertModels.js
var import_development2 = require("@daitanjs/development");
var DEFAULT_EXPERT_PROFILE_NAME = (0, import_development2.getEnvVariable)(
"DEFAULT_EXPERT_PROFILE",
"FAST_TASKER"
);
var getExpertConfig = (envVarKey, defaultValue) => {
const combinedValue = (0, import_development2.getEnvVariable)(envVarKey, defaultValue);
const parts = combinedValue.split("|");
const provider = parts[0]?.trim();
const model = parts[1]?.trim();
if (!provider || !model) {
const [defaultProvider, defaultModel] = defaultValue.split("|");
return { provider: defaultProvider.trim(), model: defaultModel.trim() };
}
return { provider, model };
};
var EXPERT_MODELS = {
MASTER_COMMUNICATOR: {
...getExpertConfig("LLM_EXPERT_MASTER_COMMUNICATOR", "openai|gpt-4o-mini"),
description: "Expert in clear, concise, and engaging communication.",
temperature: 0.7
},
CREATIVE_WRITER: {
...getExpertConfig("LLM_EXPERT_CREATIVE_WRITER", "openai|gpt-4-turbo"),
description: "Expert in creative writing, storytelling, and brainstorming.",
temperature: 0.9
},
FAST_TASKER: {
...getExpertConfig("LLM_EXPERT_FAST_TASKER", "openai|gpt-4o-mini"),
description: "Optimized for speed on less complex tasks.",
temperature: 0.5
},
LOCAL_DEFAULT: {
...getExpertConfig("LLM_EXPERT_LOCAL_DEFAULT", "ollama|llama3:instruct"),
description: "A general-purpose model running locally via Ollama.",
temperature: 0.7
},
MASTER_CODER: {
...getExpertConfig(
"LLM_EXPERT_MASTER_CODER",
"anthropic|claude-3-opus-20240229"
),
description: "Expert in code generation, debugging, and explanation.",
temperature: 0.3
},
CODING_STUDENT: {
...getExpertConfig("LLM_EXPERT_CODING_STUDENT", "openai|gpt-4o-mini"),
description: "Capable, cost-effective coding assistant for simpler tasks.",
temperature: 0.5
},
SENTIMENT_WIZARD: {
...getExpertConfig("LLM_EXPERT_SENTIMENT_WIZARD", "openai|gpt-3.5-turbo"),
description: "Specialized in sentiment analysis and understanding nuanced text.",
temperature: 0.2
},
TRANSLATION_MULTILINGUAL: {
...getExpertConfig(
"LLM_EXPERT_TRANSLATION_MULTILINGUAL",
"openai|gpt-4o-mini"
),
description: "Expert in multilingual translation.",
temperature: 0.1
},
DATA_ANALYSIS_EXPERT: {
...getExpertConfig("LLM_EXPERT_DATA_ANALYSIS", "openai|gpt-4-turbo"),
description: "Expert in interpreting data and generating insights.",
temperature: 0.4
},
RESEARCH_ASSISTANT: {
...getExpertConfig("LLM_EXPERT_RESEARCH_ASSISTANT", "openai|gpt-4-turbo"),
description: "Specialized in synthesizing information and research queries.",
temperature: 0.5
}
};
var getExpertModelDefinition = (expertName) => {
if (typeof expertName !== "string" || !expertName.trim()) return void 0;
return EXPERT_MODELS[expertName.toUpperCase()];
};
// src/intelligence/src/intelligence/core/llmPricing.js
var import_development3 = require("@daitanjs/development");
var logger = (0, import_development3.getLogger)("llm-pricing");
var PROVIDER_MODEL_PRICING = {
openai: {
"gpt-4o": { inputCostPer1MTokens: 5, outputCostPer1MTokens: 15 },
"gpt-4o-mini": { inputCostPer1MTokens: 0.15, outputCostPer1MTokens: 0.6 },
"gpt-4-turbo": { inputCostPer1MTokens: 10, outputCostPer1MTokens: 30 },
"gpt-4": { inputCostPer1MTokens: 30, outputCostPer1MTokens: 60 },
"gpt-3.5-turbo": { inputCostPer1MTokens: 0.5, outputCostPer1MTokens: 1.5 },
"text-embedding-3-large": {
inputCostPer1MTokens: 0.13,
outputCostPer1MTokens: 0
},
"text-embedding-3-small": {
inputCostPer1MTokens: 0.02,
outputCostPer1MTokens: 0
},
"text-embedding-ada-002": {
inputCostPer1MTokens: 0.1,
outputCostPer1MTokens: 0
}
},
anthropic: {
"claude-3-opus-20240229": {
inputCostPer1MTokens: 15,
outputCostPer1MTokens: 75
},
"claude-3-sonnet-20240229": {
inputCostPer1MTokens: 3,
outputCostPer1MTokens: 15
},
"claude-3-haiku-20240307": {
inputCostPer1MTokens: 0.25,
outputCostPer1MTokens: 1.25
}
},
groq: {
"llama3-8b-8192": {
inputCostPer1MTokens: 0.05,
outputCostPer1MTokens: 0.1
},
"llama3-70b-8192": {
inputCostPer1MTokens: 0.59,
outputCostPer1MTokens: 0.79
},
"mixtral-8x7b-32768": {
inputCostPer1MTokens: 0.27,
outputCostPer1MTokens: 0.27
}
},
ollama: {
"llama3:instruct": {
inputCostPer1MTokens: 0,
outputCostPer1MTokens: 0,
details: "Local model, no cost."
},
"nomic-embed-text": {
inputCostPer1MTokens: 0,
outputCostPer1MTokens: 0,
details: "Local model, no cost."
}
}
};
var estimateLlmCost = (provider, model, inputTokens = 0, outputTokens = 0) => {
const providerKey = provider?.toLowerCase();
const modelKey = model?.toLowerCase();
const result = {
estimatedCostUSD: null,
currency: "USD",
details: "No pricing information available."
};
if (!providerKey || !modelKey) {
logger.debug("Provider or model key missing for cost estimation.");
return result;
}
const providerPricing = PROVIDER_MODEL_PRICING[providerKey];
if (!providerPricing) {
result.details = `No pricing for provider '${providerKey}'.`;
return result;
}
const baseModelKey = Object.keys(providerPricing).find(
(key) => modelKey.startsWith(key)
);
if (!baseModelKey) {
result.details = `No pricing for model '${modelKey}' under provider '${providerKey}'.`;
return result;
}
const modelPricing = providerPricing[baseModelKey];
if (modelPricing.inputCostPer1MTokens === 0 && modelPricing.outputCostPer1MTokens === 0) {
result.estimatedCostUSD = 0;
result.details = modelPricing.details || "Model is free or local.";
return result;
}
const inputCost = inputTokens / 1e6 * (modelPricing.inputCostPer1MTokens || 0);
const outputCost = outputTokens / 1e6 * (modelPricing.outputCostPer1MTokens || 0);
result.estimatedCostUSD = inputCost + outputCost;
result.details = `Cost calculated for ${providerKey}/${baseModelKey}.`;
return result;
};
// src/intelligence/src/intelligence/core/tokenUtils.js
var import_tiktoken = require("tiktoken");
var import_development4 = require("@daitanjs/development");
var logger2 = (0, import_development4.getLogger)("token-utils");
var DEFAULT_CHAR_TO_TOKEN_RATIO = 4;
var tiktokenCache = /* @__PURE__ */ new Map();
var getTiktokenForModel = (modelNameInput) => {
const modelName = String(modelNameInput || "");
if (tiktokenCache.has(modelName)) {
return tiktokenCache.get(modelName);
}
let encodingName;
if (modelName.startsWith("gpt-4") || modelName.startsWith("gpt-3.5-turbo") || modelName.startsWith("text-embedding-3") || modelName.startsWith("gpt-4o")) {
encodingName = "cl100k_base";
} else if (modelName.includes("text-embedding-ada-002")) {
encodingName = "p50k_base";
} else {
logger2.debug(
`No specific tiktoken encoding for model "${modelName}". Defaulting to cl100k_base.`
);
encodingName = "cl100k_base";
}
try {
const encoding = (0, import_tiktoken.get_encoding)(encodingName);
tiktokenCache.set(modelName, encoding);
return encoding;
} catch (error) {
logger2.warn(
`Could not initialize tiktoken for model "${modelName}" (encoding: ${encodingName}): ${error.message}.`
);
return null;
}
};
var countTokens = (text, modelName, providerName = "openai") => {
if (typeof text !== "string" || text === "") return 0;
const openaiCompatibleProviders = [
"openai",
"groq",
"openrouter",
"anthropic"
];
if (openaiCompatibleProviders.includes(providerName?.toLowerCase() || "")) {
const tiktokenInstance = getTiktokenForModel(modelName);
if (tiktokenInstance) {
try {
return tiktokenInstance.encode(text).length;
} catch (error) {
logger2.warn(
`Tiktoken encoding failed for model "${modelName}". Falling back to char count.`
);
}
}
}
const estimatedTokens = Math.ceil(text.length / DEFAULT_CHAR_TO_TOKEN_RATIO);
logger2.debug(
`Using char-based token approximation for model "${modelName}" (provider: ${providerName}). Chars: ${text.length}, Approx Tokens: ${estimatedTokens}`
);
return estimatedTokens;
};
var countTokensForMessages = (messages, modelName, providerName = "openai") => {
if (!Array.isArray(messages) || messages.length === 0) return 0;
const tiktokenInstance = getTiktokenForModel(modelName);
if (!tiktokenInstance) {
let totalChars = 0;
messages.forEach((msg) => {
if (typeof msg.content === "string") {
totalChars += msg.content.length;
}
});
return Math.ceil(totalChars / DEFAULT_CHAR_TO_TOKEN_RATIO) + messages.length * 2;
}
let tokensPerMessage = 3;
let tokensPerName = 1;
let numTokens = 0;
messages.forEach((message) => {
numTokens += tokensPerMessage;
for (const key in message) {
if (key === "content" && typeof message.content === "string") {
numTokens += tiktokenInstance.encode(message.content).length;
} else if (key === "name" && message[key]) {
numTokens += tokensPerName;
}
}
});
numTokens += 3;
return numTokens;
};
// src/intelligence/src/intelligence/core/llmOrchestrator.js
var import_development5 = require("@daitanjs/development");
var logger3 = (0, import_development5.getLogger)("daitan-llm-orchestrator");
function extractJsonFromString(text) {
if (typeof text !== "string") return text;
const jsonRegex = /```(?:json)?\s*([\s\S]+?)\s*```|({[\s\S]*}|\[[\s\S]*\])/m;
const match = text.match(jsonRegex);
return match ? match[1] || match[2] || text : text;
}
var generateIntelligence = async ({
prompt = {},
config = {},
callbacks,
metadata = {}
// Add metadata to destructuring
}) => {
const {
llm: llmConfig = {},
response: responseConfig = {},
...otherConfigs
} = config;
if (!prompt.user && (!prompt.shots || prompt.shots.length === 0)) {
throw new import_error.DaitanConfigurationError(
"A `prompt.user` message or messages in `prompt.shots` are required."
);
}
let llm;
let providerName;
let modelName;
let temperature;
try {
const configManager = (0, import_config.getConfigManager)();
const rawTarget = llmConfig.target || configManager.get("DEFAULT_EXPERT_PROFILE") || configManager.get("LLM_PROVIDER") || "FAST_TASKER";
const expertDef = getExpertModelDefinition(rawTarget);
if (expertDef) {
providerName = expertDef.provider.toLowerCase();
modelName = expertDef.model;
temperature = expertDef.temperature;
} else {
const [p, m] = rawTarget.split("|");
providerName = p ? p.toLowerCase() : "openai";
modelName = m;
}
const commonConfig = {
temperature: temperature ?? llmConfig.temperature ?? 0.7,
maxRetries: config.retry?.maxAttempts ?? 2,
timeout: llmConfig.requestTimeout,
modelName
};
switch (providerName) {
case "openai": {
const apiKey = llmConfig.apiKey || configManager.get("OPENAI_API_KEY");
if (!apiKey)
throw new import_error.DaitanConfigurationError("OPENAI_API_KEY not found.");
llm = new import_openai.ChatOpenAI({ ...commonConfig, apiKey });
break;
}
case "anthropic": {
const apiKey = llmConfig.apiKey || configManager.get("ANTHROPIC_API_KEY");
if (!apiKey)
throw new import_error.DaitanConfigurationError("ANTHROPIC_API_KEY not found.");
llm = new import_anthropic.ChatAnthropic({ ...commonConfig, apiKey });
break;
}
case "groq": {
const apiKey = llmConfig.apiKey || configManager.get("GROQ_API_KEY");
if (!apiKey)
throw new import_error.DaitanConfigurationError("GROQ_API_KEY not found.");
llm = new import_groq.ChatGroq({ ...commonConfig, apiKey });
break;
}
default:
throw new import_error.DaitanConfigurationError(
`Unsupported provider in orchestrator: '${providerName}'`
);
}
const messages = buildLlmMessages(prompt);
const result = await llm.invoke(messages, { callbacks });
const rawContent = result.content ?? "";
let contentToParse = rawContent;
if (responseConfig.format === "json") {
contentToParse = extractJsonFromString(rawContent);
}
const parser = responseConfig.format === "json" ? new import_output_parsers.JsonOutputParser() : new import_output_parsers.StringOutputParser();
const finalResponse = await parser.parse(contentToParse);
const usageMetadata = result.usage_metadata ?? {};
const usage = {
inputTokens: usageMetadata.inputTokens ?? await countTokensForMessages(messages, modelName, providerName),
outputTokens: usageMetadata.outputTokens ?? await countTokens(
typeof finalResponse === "string" ? finalResponse : JSON.stringify(finalResponse ?? ""),
modelName,
providerName
)
};
usage.totalTokens = (usage.inputTokens || 0) + (usage.outputTokens || 0);
const cost = estimateLlmCost(
providerName,
modelName,
usage.inputTokens,
usage.outputTokens
);
return {
response: finalResponse,
usage: { ...usage, ...cost },
rawResponse: rawContent
};
} catch (error) {
logger3.error(
`LLM Interaction Failed. Summary: ${metadata.summary || "N/A"}. Provider: ${providerName}, Model: ${modelName}. Error: ${error.message}`,
{ errorStack: error.stack }
);
throw new import_error.DaitanApiError(
`An unrecoverable error occurred during the LLM interaction with provider '${providerName || "unknown"}'.`,
providerName || "unknown",
error?.status,
{ model: modelName, summary: metadata.summary },
error
);
}
};
// src/intelligence/src/services/llmService.js
var import_development6 = require("@daitanjs/development");
var import_config2 = require("@daitanjs/config");
var import_error2 = require("@daitanjs/error");
var logger4 = (0, import_development6.getLogger)("daitan-llm-service");
var LLMService = class {
/**
* @param {LLMServiceConfig} [defaultConfig={}] - Default configuration for this service instance.
*/
constructor(defaultConfig = {}) {
const configManager = (0, import_config2.getConfigManager)();
this.defaultConfig = {
target: configManager.get("LLM_PROVIDER", "openai"),
// Default to provider if no specific target
temperature: 0.7,
maxTokens: 2e3,
verbose: configManager.get("DEBUG_INTELLIGENCE", false),
trackUsage: configManager.get("LLM_TRACK_USAGE", true),
...defaultConfig
};
this.logger = logger4;
logger4.info("LLMService initialized.");
logger4.debug("LLMService default configuration:", this.defaultConfig);
}
/**
* Makes a generic call to `generateIntelligence`, merging service defaults with call-specific options.
* @param {GenerateIntelligenceParams} options - Options for generateIntelligence, including prompt, config, metadata, and callbacks.
* @returns {Promise<import('../intelligence/core/llmOrchestrator.js').GenerateIntelligenceResult<any>>}
*/
async generate(options) {
const {
prompt = {},
config: callConfig = {},
metadata = {},
callbacks
} = options;
if (!prompt?.user && !(prompt?.shots && prompt.shots.length > 0)) {
throw new import_error2.DaitanInvalidInputError(
"LLMService.generate: A `prompt.user` message or messages in `prompt.shots` are required."
);
}
const {
llm: callLlm = {},
response: callResponse = {},
retry: callRetry = {},
...callRootConfig
} = callConfig;
const finalConfig = {
verbose: this.defaultConfig.verbose,
trackUsage: this.defaultConfig.trackUsage,
...callRootConfig,
llm: {
target: this.defaultConfig.target,
temperature: this.defaultConfig.temperature,
maxTokens: this.defaultConfig.maxTokens,
apiKey: this.defaultConfig.apiKey,
baseURL: this.defaultConfig.baseURL,
...callLlm
},
response: { ...callResponse },
retry: {
maxAttempts: this.defaultConfig.maxRetries,
...callRetry
}
};
const finalParams = {
prompt,
config: finalConfig,
metadata,
callbacks
};
const summary = metadata?.summary || "Untitled LLMService Call";
this.logger.info(`LLMService.generate called for summary: "${summary}"`);
try {
const result = await generateIntelligence(finalParams);
this.logger.info(`LLMService.generate successful for: "${summary}"`);
if (result.usage) {
this.logger.debug("LLM Usage:", result.usage);
}
return result;
} catch (error) {
this.logger.error(
`LLMService.generate failed for "${summary}": ${error.message}`,
{ error }
);
throw error;
}
}
/**
* Generates a JSON response from the LLM.
* @param {Object} params
* @returns {Promise<{response: Object, usage: LLMUsageInfo | null}>}
*/
async generateJson({
userPrompt,
whoYouAre,
whatYouDo,
summary = "JSON Generation",
shots,
...overrideConfig
}) {
const { target, temperature, maxTokens, apiKey, baseURL, ...rootConfig } = overrideConfig;
const params = {
prompt: {
system: { persona: whoYouAre, task: whatYouDo },
user: userPrompt,
shots
},
config: {
...rootConfig,
response: { format: "json" },
llm: { target, temperature, maxTokens, apiKey, baseURL }
},
metadata: { summary }
};
return this.generate(params);
}
/**
* Generates a text response from the LLM.
* @param {Object} params
* @returns {Promise<{response: string, usage: LLMUsageInfo | null}>}
*/
async generateText({
userPrompt,
whoYouAre,
whatYouDo,
summary = "Text Generation",
shots,
...overrideConfig
}) {
const { target, temperature, maxTokens, apiKey, baseURL, ...rootConfig } = overrideConfig;
const params = {
prompt: {
system: { persona: whoYouAre, task: whatYouDo },
user: userPrompt,
shots
},
config: {
...rootConfig,
response: { format: "text" },
llm: { target, temperature, maxTokens, apiKey, baseURL }
},
metadata: { summary }
};
return this.generate(params);
}
/**
* Streams a text response from the LLM.
* @param {Object} params
* @returns {Promise<{response: string | undefined, usage: LLMUsageInfo | null}>}
*/
async streamText({
userPrompt,
whoYouAre,
whatYouDo,
summary = "Text Streaming",
shots,
callbacks,
returnFullResponseAfterStream = true,
...overrideConfig
}) {
if (!callbacks || typeof callbacks.onTokenStream !== "function") {
throw new import_error2.DaitanInvalidInputError(
"LLMService.streamText: `callbacks.onTokenStream` is required for streaming."
);
}
const { target, temperature, maxTokens, apiKey, baseURL, ...rootConfig } = overrideConfig;
const params = {
prompt: {
system: { persona: whoYouAre, task: whatYouDo },
user: userPrompt,
shots
},
config: {
...rootConfig,
response: { format: "text", returnFullResponseAfterStream },
llm: { target, temperature, maxTokens, apiKey, baseURL }
},
metadata: { summary },
callbacks
};
return this.generate(params);
}
};
// src/intelligence/src/intelligence/index.js
var import_development46 = require("@daitanjs/development");
// src/intelligence/src/intelligence/core/embeddingGenerator.js
var import_development7 = require("@daitanjs/development");
var import_embeddings = require("@daitanjs/embeddings");
var embeddingGeneratorLogger = (0, import_development7.getLogger)("daitan-embedding-generator");
embeddingGeneratorLogger.info(
"Embedding generator module is a re-export layer. All embedding functionalities are canonical in @daitanjs/embeddings."
);
// src/intelligence/src/intelligence/core/toolFactory.js
var import_tools = require("@langchain/core/tools");
var import_development8 = require("@daitanjs/development");
var import_error3 = require("@daitanjs/error");
var import_zod = require("zod");
var toolFactoryLogger = (0, import_development8.getLogger)("daitan-tool-factory");
var createDaitanTool = (name, description, func, argsSchema = void 0) => {
if (!name || typeof name !== "string" || !name.trim()) {
throw new import_error3.DaitanInvalidInputError(
"Tool `name` must be a non-empty string."
);
}
if (!description || typeof description !== "string" || !description.trim()) {
throw new import_error3.DaitanInvalidInputError(
"Tool `description` must be a non-empty string."
);
}
if (typeof func !== "function") {
throw new import_error3.DaitanInvalidInputError(
"Tool `func` must be a callable function."
);
}
const daitanToolWrapperFunc = async (rawInput) => {
const callId = `tool-run-${name}-${Date.now().toString(36)}`;
const logger13 = (0, import_development8.getLogger)(`daitan-tool-${name}`);
logger13.info(`Tool "${name}" execution: START`, { callId, rawInput });
let inputForRun = rawInput;
try {
if (typeof rawInput === "string") {
try {
inputForRun = JSON.parse(rawInput);
} catch (e) {
}
}
if (argsSchema) {
inputForRun = argsSchema.parse(inputForRun);
}
const result = await func(inputForRun, callId);
const outputString = typeof result === "string" ? result : JSON.stringify(result, null, 2);
logger13.info(`Tool "${name}" execution: SUCCESS`, {
callId,
outputPreview: outputString.substring(0, 150) + "..."
});
return outputString;
} catch (error) {
logger13.error(`Execution error in tool "${name}": ${error.message}`, {
callId,
errorName: error.name
});
if (error instanceof import_zod.ZodError) {
const validationErrorMessage = "Invalid input. " + error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join("; ");
return `Error: ${validationErrorMessage}`;
}
if (error instanceof import_error3.DaitanValidationError || error instanceof import_error3.DaitanOperationError) {
return `Error: ${error.message}`;
}
return `Error executing tool "${name}": An unexpected error occurred. ${error.message}`;
}
};
const toolConfig = {
name: name.trim(),
description: description.trim(),
func: daitanToolWrapperFunc,
schema: argsSchema
};
return new import_tools.DynamicTool(toolConfig);
};
// src/intelligence/src/intelligence/rag/index.js
var import_development21 = require("@daitanjs/development");
// src/intelligence/src/intelligence/rag/retrieval.js
var import_path = __toESM(require("path"), 1);
// src/intelligence/src/intelligence/rag/vectorStoreFactory.js
var import_development12 = require("@daitanjs/development");
var import_config6 = require("@daitanjs/config");
var import_error7 = require("@daitanjs/error");
// src/intelligence/src/intelligence/rag/chromaVectorStoreAdapter.js
var import_chroma = require("@langchain/community/vectorstores/chroma");
var import_openai2 = require("@langchain/openai");
var import_development10 = require("@daitanjs/development");
var import_config4 = require("@daitanjs/config");
var import_error5 = require("@daitanjs/error");
// src/intelligence/src/intelligence/rag/chromaClient.js
var import_chromadb = require("chromadb");
var import_development9 = require("@daitanjs/development");
var import_config3 = require("@daitanjs/config");
var import_error4 = require("@daitanjs/error");
var logger5 = (0, import_development9.getLogger)("daitan-rag-chroma-client");
var getChromaHost = () => (0, import_config3.getConfigManager)().get("CHROMA_HOST", "localhost");
var getChromaPort = () => (0, import_config3.getConfigManager)().get("CHROMA_PORT", 8e3);
var getDefaultCollectionName = () => (0, import_config3.getConfigManager)().get(
"RAG_DEFAULT_COLLECTION_NAME",
"daitan_rag_default_store"
);
var chromaClientInstance = null;
var checkChromaConnection = async (timeoutMs = 3e3) => {
const host = getChromaHost();
const port = getChromaPort();
const endpointsToTry = [
`http://${host}:${port}/api/v2/heartbeat`,
`http://${host}:${port}/api/v1/heartbeat`
];
for (const url of endpointsToTry) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeoutId);
if (response.ok) {
logger5.info(`ChromaDB connection successful on endpoint: ${url}`);
return true;
}
} catch (error) {
}
}
logger5.error(`ChromaDB connection check failed on all attempted endpoints.`);
return false;
};
async function getOrInitializeChromaClient() {
if (chromaClientInstance) {
try {
await chromaClientInstance.heartbeat();
return chromaClientInstance;
} catch (error) {
logger5.warn(
"Existing ChromaDB client connection is stale, re-initializing..."
);
chromaClientInstance = null;
}
}
const host = getChromaHost();
const port = getChromaPort();
const baseUrl = `http://${host}:${port}`;
try {
if (!await checkChromaConnection()) {
throw new import_error4.DaitanOperationError(
`Could not connect to ChromaDB server at ${baseUrl}.`
);
}
chromaClientInstance = new import_chromadb.ChromaClient({ path: baseUrl });
await chromaClientInstance.heartbeat();
logger5.info(`ChromaDB client initialized and connection confirmed.`);
} catch (error) {
chromaClientInstance = null;
throw new import_error4.DaitanOperationError(
`Failed to initialize ChromaDB client: ${error.message}`,
{ host, port },
error
);
}
return chromaClientInstance;
}
// src/intelligence/src/intelligence/rag/chromaVectorStoreAdapter.js
var adapterLogger = (0, import_development10.getLogger)("daitan-chroma-adapter");
var ChromaVectorStoreAdapter = class {
constructor({ collectionName, url, embeddings, verbose }) {
if (!collectionName) {
throw new import_error5.DaitanConfigurationError(
"ChromaVectorStoreAdapter: collectionName is required."
);
}
this.collectionName = collectionName;
this.initialConfig = { url, embeddings, verbose };
this.isInitialized = false;
this.directClient = null;
this.langchainStoreInstance = null;
}
/**
* Initializes the adapter on its first use. This lazy initialization
* prevents unnecessary connections and configuration lookups.
* @private
*/
async _lazyInitialize() {
if (this.isInitialized) return;
const configManager = (0, import_config4.getConfigManager)();
this.verbose = this.initialConfig.verbose ?? configManager.get("CHROMA_ADAPTER_VERBOSE", false);
this.url = this.initialConfig.url || `http://${configManager.get(
"CHROMA_HOST",
"localhost"
)}:${configManager.get("CHROMA_PORT", "8000")}`;
this.embeddings = this.initialConfig.embeddings || this._resolveDefaultEmbeddings(configManager);
if (!this.embeddings) {
throw new import_error5.DaitanConfigurationError(
"Embeddings must be provided or OpenAI default must be configurable (OPENAI_API_KEY is missing)."
);
}
this.directClient = await getOrInitializeChromaClient();
this.langchainStoreInstance = new import_chroma.Chroma(this.embeddings, {
collectionName: this.collectionName,
url: this.url
});
this.isInitialized = true;
adapterLogger.info(
`ChromaVectorStoreAdapter for "${this.collectionName}" has been initialized on first use.`
);
}
/**
* Creates a default OpenAI embeddings instance if none is provided.
* @private
*/
_resolveDefaultEmbeddings(configManager) {
const apiKey = configManager.get("OPENAI_API_KEY");
if (!apiKey) {
adapterLogger.warn(
"Cannot create default OpenAIEmbeddings: OPENAI_API_KEY is not configured."
);
return null;
}
const ragEmbeddingModel = configManager.get(
"RAG_EMBEDDING_MODEL_OPENAI",
"text-embedding-3-small"
);
return new import_openai2.OpenAIEmbeddings({
apiKey,
model: ragEmbeddingModel
});
}
async addDocuments(documents, options = {}) {
await this._lazyInitialize();
try {
return await this.langchainStoreInstance.addDocuments(
documents,
options.ids ? { ids: options.ids } : void 0
);
} catch (error) {
throw new import_error5.DaitanOperationError(
`Failed to add documents to collection "${this.collectionName}": ${error.message}`,
{ collectionName: this.collectionName },
error
);
}
}
async similaritySearchWithScore(query, k = 4, filter) {
await this._lazyInitialize();
try {
return await this.langchainStoreInstance.similaritySearchWithScore(
query,
k,
filter
);
} catch (error) {
throw new import_error5.DaitanOperationError(
`Failed to perform similarity search in collection "${this.collectionName}": ${error.message}`,
{ collectionName: this.collectionName, query, k },
error
);
}
}
async collectionExists() {
await this._lazyInitialize();
try {
await this.directClient.getCollection({ name: this.collectionName });
return true;
} catch (error) {
const errorMessage = String(error.message).toLowerCase();
if (errorMessage.includes("not found") || errorMessage.includes("does not exist")) {
return false;
}
throw new import_error5.DaitanOperationError(
`Failed to check for collection "${this.collectionName}": ${error.message}`,
{ host: this.url, collectionName: this.collectionName },
error
);
}
}
async deleteCollection() {
await this._lazyInitialize();
try {
await this.directClient.deleteCollection({ name: this.collectionName });
this.isInitialized = false;
this.langchainStoreInstance = null;
adapterLogger.info(
`Collection "${this.collectionName}" deleted successfully.`
);
} catch (error) {
const errorMessage = String(error.message).toLowerCase();
if (!errorMessage.includes("not found") && !errorMessage.includes("does not exist")) {
throw new import_error5.DaitanOperationError(
`Failed to delete Chroma collection "${this.collectionName}": ${error.message}`,
{ collectionName: this.collectionName },
error
);
}
adapterLogger.info(
`Collection "${this.collectionName}" was already deleted or doesn't exist.`
);
}
}
async getCollectionInfo() {
await this._lazyInitialize();
try {
const collection = await this.directClient.getCollection({
name: this.collectionName
});
const count = await collection.count();
return {
name: collection.name,
id: collection.id,
count,
metadata: collection.metadata
};
} catch (error) {
throw new import_error5.DaitanOperationError(
`Failed to get collection info for "${this.collectionName}": ${error.message}`,
{ collectionName: this.collectionName },
error
);
}
}
async clearCollection() {
await this._lazyInitialize();
try {
const collection = await this.directClient.getCollection({
name: this.collectionName
});
const result = await collection.get();
if (result.ids && result.ids.length > 0) {
await collection.delete({ ids: result.ids });
adapterLogger.info(
`Cleared ${result.ids.length} documents from collection "${this.collectionName}".`
);
} else {
adapterLogger.info(
`Collection "${this.collectionName}" is already empty.`
);
}
} catch (error) {
throw new import_error5.DaitanOperationError(
`Failed to clear collection "${this.collectionName}": ${error.message}`,
{ collectionName: this.collectionName },
error
);
}
}
async getLangchainStore() {
await this._lazyInitialize();
return this.langchainStoreInstance;
}
};
// src/intelligence/src/intelligence/rag/memoryVectorStoreAdapter.js
var import_memory = require("langchain/vectorstores/memory");
var import_openai3 = require("@langchain/openai");
var import_development11 = require("@daitanjs/development");
var import_config5 = require("@daitanjs/config");
var import_error6 = require("@daitanjs/error");
var import_documents = require("@langchain/core/documents");
var memoryAdapterLogger = (0, import_development11.getLogger)("daitan-memory-vstore-adapter");
var MemoryVectorStoreAdapter = class {
/**
* @param {Object} [config={}]
* @param {import('@langchain/core/embeddings').Embeddings} [config.embeddings] - LangChain embeddings instance.
* @param {LangchainDocument[]} [config.initialDocuments=[]] - Optional documents to initialize with.
* @param {boolean} [config.verbose] - Verbose logging for this instance. Defaults from ConfigManager.
* @throws {DaitanConfigurationError} If embeddings cannot be configured.
*/
constructor({
embeddings,
// Renamed from embeddingsInstance
initialDocuments = [],
verbose
} = {}) {
const configManager = (0, import_config5.getConfigManager)();
this.verbose = verbose !== void 0 ? verbose : configManager.get("MEMORY_ADAPTER_VERBOSE", false) || configManager.get("DEBUG_INTELLIGENCE", false);
this.embeddings = embeddings || this._resolveDefaultEmbeddings();
if (!this.embeddings) {
const errMsg = "MemoryVectorStoreAdapter: Embeddings must be provided, or OpenAI default embeddings must be configurable (requires OPENAI_API_KEY via ConfigManager).";
memoryAdapterLogger.error(errMsg);
throw new import_error6.DaitanConfigurationError(errMsg);
}
this.store = null;
if (this.verbose) {
memoryAdapterLogger.info(
`MemoryVectorStoreAdapter initialized. Verbose: ${this.verbose}. Embeddings: ${this.embeddings.constructor.name}`
);
}
if (initialDocuments && initialDocuments.length > 0) {
this._initializeWithDocuments(initialDocuments).catch((err) => {
memoryAdapterLogger.error(
`MemoryVectorStoreAdapter: Background initialization with documents failed: ${err.message}`
);
});
}
}
/**
* Sets the verbosity for this adapter instance.
* @param {boolean} isVerbose
*/
setVerbose(isVerbose) {
this.verbose = isVerbose;
memoryAdapterLogger.info(
`MemoryVectorStoreAdapter verbosity set to: ${this.verbose}`
);
}
_resolveDefaultEmbeddings() {
const configManager = (0, import_config5.getConfigManager)();
const apiKey = configManager.get("OPENAI_API_KEY");
if (!apiKey) {
memoryAdapterLogger.warn(
"MemoryVectorStoreAdapter: OPENAI_API_KEY not found via ConfigManager for default OpenAIEmbeddings."
);
return null;
}
try {
const ragEmbeddingModel = configManager.get("RAG_EMBEDDING_MODEL_OPENAI");
const embeddingsConfig = { apiKey };
if (ragEmbeddingModel) {
embeddingsConfig.modelName = ragEmbeddingModel;
}
if (this.verbose)
memoryAdapterLogger.debug(
`Using OpenAIEmbeddings with model: ${ragEmbeddingModel || "default (text-embedding-ada-002 or similar)"}`
);
return new import_openai3.OpenAIEmbeddings(embeddingsConfig);
} catch (e) {
memoryAdapterLogger.error(
`Failed to instantiate default OpenAIEmbeddings: ${e.message}`
);
return null;
}
}
async _initializeWithDocuments(documents) {
if (this.store) {
if (this.verbose)
memoryAdapterLogger.debug(
"MemoryVectorStore already initialized, skipping re-initialization with documents."
);
return;
}
try {
if (this.verbose)
memoryAdapterLogger.debug(
`MemoryVectorStore: Initializing via fromDocuments with ${documents.length} documents.`
);
this.store = await import_memory.MemoryVectorStore.fromDocuments(
documents,
this.embeddings
);
if (this.verbose)
memoryAdapterLogger.debug(
`MemoryVectorStore initialized successfully with ${documents.length} documents.`
);
} catch (error) {
memoryAdapterLogger.error(
`MemoryVectorStoreAdapter: Error during fromDocuments initialization: ${error.message}`,
{ error_stack: error.stack?.substring(0, 300) }
);
}
}
async _ensureStoreIsInitialized() {
if (!this.store) {
if (this.verbose)
memoryAdapterLogger.debug(
"MemoryVectorStoreAdapter: Store not yet initialized. Lazily creating empty store now."
);
try {
this.store = new import_memory.MemoryVectorStore(this.embeddings);
if (this.verbose)
memoryAdapterLogger.debug(
"MemoryVectorStoreAdapter: Empty store created successfully."
);
} catch (error) {
memoryAdapterLogger.error(
`MemoryVectorStoreAdapter: Error creating empty MemoryVectorStore instance: ${error.message}`,
{ error_stack: error.stack?.substring(0, 300) }
);
throw new import_error6.DaitanOperationError(
"Failed to create empty MemoryVectorStore",
{},
error
);
}
}
}
async addDocuments(documents, options = {}) {
if (!Array.isArray(documents) || documents.length === 0) {
if (this.verbose)
memoryAdapterLogger.info(
"MemoryAdapter: No documents provided to add."
);
return;
}
await this._ensureStoreIsInitialized();
if (this.verbose)
memoryAdapterLogger.info(
`MemoryAdapter: Adding ${documents.length} documents.`
);
try {
await this.store.addDocuments(
documents,
options.ids ? { ids: options.ids } : void 0
);
if (this.verbose)
memoryAdapterLogger.debug(
`MemoryAdapter: Successfully added ${documents.length} documents.`
);
} catch (error) {
memoryAdapterLogger.error(
`MemoryAdapter: Error adding documents: ${error.message}`,
{
numDocs: documents.length,
error_stack: error.stack?.substring(0, 300)
}
);
throw new import_error6.DaitanOperationError(
"Failed to add documents to MemoryVectorStore",
{},
error
);
}
}
async similaritySearchWithScore(query, k, filter) {
await this._ensureStoreIsInitialized();
const logContext = {
queryPreview: String(query).substring(0, 70) + "...",
k
};
if (this.verbose) {
memoryAdapterLogger.debug("MemoryAdapter: Similarity search started.", {
...logContext,
filter: filter ? typeof filter === "function" ? "Function filter" : filter : "None"
});
}
let adaptedFilter = filter;
if (filter && typeof filter === "object" && !Array.isArray(filter) && typeof filter !== "function") {
adaptedFilter = (doc) => {
for (const key in filter) {
if (!doc.metadata || doc.metadata[key] !== filter[key]) return false;
}
return true;
};
if (this.verbose)
memoryAdapterLogger.debug(
"MemoryAdapter: Adapted object metadata filter to function for similaritySearch."
);
} else if (typeof filter !== "function" && filter !== void 0) {
memoryAdapterLogger.warn(
"MemoryAdapter: Filter provided is not a metadata object or function. It will be ignored by MemoryVectorStore for similaritySearchWithScore.",
{ filterType: typeof filter }
);
adaptedFilter = void 0;
}
try {
const results = await this.store.similaritySearchWithScore(
query,
k,
adaptedFilter
);
if (this.verbose)
memoryAdapterLogger.debug(
`MemoryAdapter: Similarity search returned ${results.length} results.`
);
return results;
} catch (error) {
memoryAdapterLogger.error(
`MemoryAdapter: Similarity search error: ${error.message}`,
{ ...logContext, error_stack: error.stack?.substring(0, 300) }
);
throw new import_error6.DaitanOperationError(
"Similarity search failed in MemoryVectorStore",
logContext,
error
);
}
}
async collectionExists(collectionNameIgnored) {
await this._ensureStoreIsInitialized();
if (this.verbose)
memoryAdapterLogger.debug(
`MemoryAdapter: "collectionExists" check - returning ${!!this.store}.`
);
return !!this.store;
}
async ensureCollection(collectionNameIgnored, options = {}) {
await this._ensureStoreIsInitialized();
if (this.verbose)
memoryAdapterLogger.debug(
'MemoryAdapter: "ensureCollection" called. Store is ready or will be created.'
);
}
async deleteCollection(collectionNameIgnored) {
if (this.verbose)
memoryAdapterLogger.info(
'MemoryAdapter: "Deleting collection" - re-initializing to an empty store.'
);
try {
this.store = new import_memory.MemoryVectorStore(this.embeddings);
if (this.verbose)
memoryAdapterLogger.debug(
"MemoryAdapter: Store re-initialized (effectively cleared)."
);
} catch (error) {
memoryAdapterLogger.error(
`MemoryAdapter: Error re-initializing store during deleteCollection: ${error.message}`,
{ error_stack: error.stack?.substring(0, 300) }
);
throw new import_error6.DaitanOperationError(
"Failed to clear/re-initialize MemoryVectorStore",
{},
error
);
}
}
async getLangchainStore() {
await this._ensureStoreIsInitialized();
return this.store;
}
};
// src/intelligence/src/intelligence/rag/vectorStoreFactory.js
var vectorStoreLogger = (0, import_development12.getLogger)("daitan-rag-vectorstore");
var FALLBACK_DEFAULT_COLLECTION_NAME = "daitan_rag_default_store";
var DEFAULT_COLLECTION_NAME = () => {
const configManager = (0, import_config6.getConfigManager)();
return configManager.get("RAG_DEFAULT_COLLECTION_NAME") || getDefaultCollectionName() || FALLBACK_DEFAULT_COLLECTION_NAME;
};
var currentModuleVerbose = false;
var vectorStoreAdapterSingleton = null;
var getVectorS