@xynehq/jaf
Version:
Juspay Agent Framework - A purely functional agent framework with immutable state and composable tools
220 lines • 8 kB
JavaScript
/**
* JAF ADK Layer - Content System
*
* Functional content and message handling utilities
*/
// ========== Content Creation ==========
export const createContent = (role, text, metadata) => ({
role,
parts: [createTextPart(text)],
metadata
});
export const createUserMessage = (text, metadata) => createContent('user', text, metadata);
export const createModelMessage = (text, metadata) => createContent('model', text, metadata);
export const createSystemMessage = (text, metadata) => createContent('system', text, metadata);
// ========== Part Creation ==========
export const createTextPart = (text, metadata) => ({
type: 'text',
text,
metadata
});
export const createImagePart = (data, metadata) => ({
type: 'image',
data,
metadata
});
export const createAudioPart = (data, metadata) => ({
type: 'audio',
data,
metadata
});
export const createFunctionCallPart = (functionCall, metadata) => ({
type: 'function_call',
functionCall,
metadata
});
export const createFunctionResponsePart = (functionResponse, metadata) => ({
type: 'function_response',
functionResponse,
metadata
});
// ========== Function Call/Response Creation ==========
export const createFunctionCall = (id, name, args) => ({
id,
name,
args
});
export const createFunctionResponse = (id, name, response, success = true, error) => ({
id,
name,
response,
success,
error
});
// ========== Content Manipulation ==========
export const addPart = (content, part) => ({
...content,
parts: [...content.parts, part]
});
export const addTextPart = (content, text) => addPart(content, createTextPart(text));
export const addFunctionCall = (content, functionCall) => addPart(content, createFunctionCallPart(functionCall));
export const addFunctionResponse = (content, functionResponse) => addPart(content, createFunctionResponsePart(functionResponse));
// ========== Content Query Functions ==========
export const getTextContent = (content) => {
return content.parts
.filter(part => part.type === 'text' && part.text)
.map(part => part.text)
.join('');
};
export const getFunctionCalls = (content) => {
return content.parts
.filter(part => part.type === 'function_call' && part.functionCall)
.map(part => part.functionCall)
.filter(Boolean);
};
export const getFunctionResponses = (content) => {
return content.parts
.filter(part => part.type === 'function_response' && part.functionResponse)
.map(part => part.functionResponse)
.filter(Boolean);
};
export const hasTextContent = (content) => {
return content.parts.some(part => part.type === 'text' && part.text);
};
export const hasFunctionCalls = (content) => {
return content.parts.some(part => part.type === 'function_call');
};
export const hasFunctionResponses = (content) => {
return content.parts.some(part => part.type === 'function_response');
};
// ========== Content Conversion ==========
export const contentToString = (content) => {
const textContent = getTextContent(content);
const functionCalls = getFunctionCalls(content);
const functionResponses = getFunctionResponses(content);
let result = textContent;
if (functionCalls.length > 0) {
const callsStr = functionCalls
.map(call => `[FUNCTION_CALL: ${call.name}(${JSON.stringify(call.args)})]`)
.join(' ');
result += (result ? ' ' : '') + callsStr;
}
if (functionResponses.length > 0) {
const responsesStr = functionResponses
.map(response => `[FUNCTION_RESPONSE: ${response.name} -> ${JSON.stringify(response.response)}]`)
.join(' ');
result += (result ? ' ' : '') + responsesStr;
}
return result;
};
export const parseContent = (raw) => {
if (typeof raw === 'string') {
return createUserMessage(raw);
}
if (typeof raw === 'object' && raw !== null) {
// Try to parse as existing Content object
if ('role' in raw && 'parts' in raw) {
return raw;
}
// Try to parse as simple message object
if ('text' in raw || 'message' in raw) {
const text = raw.text || raw.message;
const role = raw.role || 'user';
return createContent(role, text);
}
}
throw new Error(`Cannot parse content from: ${JSON.stringify(raw)}`);
};
// ========== Content Validation ==========
export const isValidContent = (content) => {
if (typeof content !== 'object' || content === null) {
return false;
}
const c = content;
return (typeof c.role === 'string' &&
['user', 'model', 'system'].includes(c.role) &&
Array.isArray(c.parts) &&
c.parts.every(isValidPart));
};
export const isValidPart = (part) => {
if (typeof part !== 'object' || part === null) {
return false;
}
const p = part;
return (typeof p.type === 'string' &&
['text', 'image', 'audio', 'function_call', 'function_response'].includes(p.type));
};
// ========== Content Utilities ==========
export const mergeContent = (...contents) => {
if (contents.length === 0) {
return createUserMessage('');
}
if (contents.length === 1) {
return contents[0];
}
const [first, ...rest] = contents;
const allParts = [first, ...rest].flatMap(c => c.parts);
return {
...first,
parts: allParts
};
};
export const cloneContent = (content) => ({
...content,
parts: content.parts.map(part => ({ ...part })),
metadata: content.metadata ? { ...content.metadata } : undefined
});
export const filterContentByRole = (contents, role) => {
return contents.filter(content => content.role === role);
};
export const getLastUserMessage = (contents) => {
const userMessages = filterContentByRole(contents, 'user');
return userMessages.length > 0 ? userMessages[userMessages.length - 1] : null;
};
export const getLastModelMessage = (contents) => {
const modelMessages = filterContentByRole(contents, 'model');
return modelMessages.length > 0 ? modelMessages[modelMessages.length - 1] : null;
};
// ========== Content Statistics ==========
export const getContentStats = (content) => {
const textParts = content.parts.filter(p => p.type === 'text').length;
const imageParts = content.parts.filter(p => p.type === 'image').length;
const audioParts = content.parts.filter(p => p.type === 'audio').length;
const functionCallParts = content.parts.filter(p => p.type === 'function_call').length;
const functionResponseParts = content.parts.filter(p => p.type === 'function_response').length;
const textLength = getTextContent(content).length;
return {
totalParts: content.parts.length,
textParts,
imageParts,
audioParts,
functionCallParts,
functionResponseParts,
textLength,
hasMedia: imageParts > 0 || audioParts > 0,
hasFunctions: functionCallParts > 0 || functionResponseParts > 0
};
};
export const getConversationStats = (contents) => {
const userMessages = filterContentByRole(contents, 'user').length;
const modelMessages = filterContentByRole(contents, 'model').length;
const systemMessages = filterContentByRole(contents, 'system').length;
const totalTextLength = contents
.map(getTextContent)
.reduce((sum, text) => sum + text.length, 0);
const totalFunctionCalls = contents
.flatMap(getFunctionCalls).length;
const totalFunctionResponses = contents
.flatMap(getFunctionResponses).length;
return {
totalMessages: contents.length,
userMessages,
modelMessages,
systemMessages,
totalTextLength,
totalFunctionCalls,
totalFunctionResponses,
averageMessageLength: contents.length > 0 ? totalTextLength / contents.length : 0
};
};
//# sourceMappingURL=index.js.map