Skip to content

Instantly share code, notes, and snippets.

@jiggyjo11
Created May 21, 2025 10:25
Show Gist options
  • Save jiggyjo11/4328127b82f40a58f40e9ac6a44bf3df to your computer and use it in GitHub Desktop.
Save jiggyjo11/4328127b82f40a58f40e9ac6a44bf3df to your computer and use it in GitHub Desktop.
import {
Action,
IAgentRuntime,
logger,
Memory,
State,
HandlerCallback,
ModelType,
} from '@elizaos/core';
const quantitativePromptTemplate = `# Task: Extract and validate numeric data from the following text.
Text: {{text}}
# Instructions:
1. Identify any numbers with units (mg, g, kg, ml, l, μl, μM, mM, M, $)
2. For each number found, list it in markdown format:
- Value: [number]
- Unit: [unit]
- Type: [concentration/volume/weight/cost]
3. Only extract numbers that are explicitly stated
4. Do not make assumptions or calculations
# Response Format:
Return a markdown list. Each item should be formatted like this:
- Value: 100
Unit: μM
Type: concentration
- Value: 5
Unit: ml
Type: volume
Example valid response:
- Value: 100
Unit: μM
Type: concentration
- Value: 5
Unit: ml
Type: volume`;
export const quantitativeActions = {
DETECT_QUANTITATIVE: {
name: 'DETECT_QUANTITATIVE',
similes: ['PROCESS_NUMBERS', 'ANALYZE_MEASUREMENTS', 'EXTRACT_QUANTITIES'],
description:
'Detects and processes numeric content in messages, including measurements and quantities',
validate: async (runtime: IAgentRuntime, message: Memory, state: State): Promise<boolean> => {
logger.warn('=== DETECT_QUANTITATIVE VALIDATE START ===');
try {
const text = message.content.text?.toLowerCase() || '';
logger.warn('Validate received text:', { text });
// Check if we've already processed this message
const messageId = message.id;
if (state.data?.processedMessages?.includes(messageId)) {
logger.warn('Message already processed', { messageId });
return false;
}
// Filter out Discord mentions in the format (@1368906455100559415)
const filteredText = text.replace(/\(@\d+\)/g, '');
// Simple check for numbers and units
const hasNumeric = /\d+(?:\s*(?:mg|g|kg|ml|l|μl|μM|mM|M|\$))?/i.test(filteredText);
logger.warn('Numeric content detection result', { hasNumeric });
return hasNumeric;
} catch (error) {
logger.error('Error validating quantitative content:', error);
return false;
}
},
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
_options: any,
callback: HandlerCallback
): Promise<void> => {
logger.warn('=== DETECT_QUANTITATIVE HANDLER START ===');
try {
const text = message.content.text || '';
logger.warn('Handler received text:', { text });
// Use the prompt template to extract numeric data
const prompt = quantitativePromptTemplate.replace('{{text}}', text);
logger.warn('Using prompt:', { prompt });
const model = runtime.getModel(ModelType.TEXT_LARGE);
if (!model) {
logger.error('Model not found');
throw new Error('Text generation model not found');
}
logger.warn('Calling model...');
let response;
try {
response = await model(runtime, { prompt });
logger.warn('Model call completed');
} catch (error) {
logger.error('Error calling model:', error);
throw error;
}
if (!response) {
logger.error('Model returned empty response');
throw new Error('Model returned empty response');
}
// Log the raw response
logger.warn('Raw model response:', { response });
// Parse the markdown response
const numericData = [];
const lines = response.split('\n');
let currentItem = null;
for (const line of lines) {
const trimmedLine = line.trim();
if (trimmedLine.startsWith('- Value:')) {
if (currentItem) {
numericData.push(currentItem);
}
currentItem = { value: null, unit: null, type: null };
const valueMatch = trimmedLine.match(/Value:\s*([\d.]+)/);
if (valueMatch) {
currentItem.value = parseFloat(valueMatch[1]);
}
} else if (trimmedLine.startsWith('Unit:')) {
if (currentItem) {
const unitMatch = trimmedLine.match(/Unit:\s*([^\n]+)/);
if (unitMatch) {
currentItem.unit = unitMatch[1].trim();
}
}
} else if (trimmedLine.startsWith('Type:')) {
if (currentItem) {
const typeMatch = trimmedLine.match(/Type:\s*([^\n]+)/);
if (typeMatch) {
currentItem.type = typeMatch[1].trim();
}
}
}
}
// Add the last item if exists
if (currentItem) {
numericData.push(currentItem);
}
// Filter out incomplete items
const validNumericData = numericData.filter(
(item) => item.value !== null && item.unit !== null && item.type !== null
);
logger.warn('Parsed numeric data:', { validNumericData });
// Create memory of processing
await runtime.createMemory(
{
entityId: runtime.agentId,
agentId: runtime.agentId,
roomId: message.roomId,
content: {
text: message.content.text,
actions: ['DETECT_QUANTITATIVE'],
metadata: {
numericData: validNumericData,
hasValidData: validNumericData.length > 0,
},
},
createdAt: Date.now(),
},
'messages'
);
// Pass results through callback
await callback({
actions: ['DETECT_QUANTITATIVE'],
metadata: {
numericData: validNumericData,
hasValidData: validNumericData.length > 0,
},
});
logger.warn('Numeric content processing complete', {
dataCount: validNumericData.length,
});
// Mark message as processed
if (!state.data.processedMessages) {
state.data.processedMessages = [];
}
state.data.processedMessages.push(message.id);
} catch (error) {
logger.error('Error processing numeric content:', error);
await runtime.createMemory(
{
entityId: runtime.agentId,
agentId: runtime.agentId,
roomId: message.roomId,
content: {
text: message.content.text,
actions: ['DETECT_QUANTITATIVE'],
metadata: {
error: error.message,
},
},
createdAt: Date.now(),
},
'messages'
);
await callback({
actions: ['DETECT_QUANTITATIVE'],
metadata: {
error: error.message,
},
});
}
},
examples: [
[
{
name: '{{name1}}',
content: {
text: 'I need 5mg of substance X',
source: 'discord',
},
},
{
name: '{{name2}}',
content: {
text: 'Processed quantity: 5mg',
actions: ['DETECT_QUANTITATIVE'],
metadata: {
numericData: [{ value: 5, unit: 'mg', type: 'weight' }],
hasValidData: true,
},
},
},
],
[
{
name: '{{name1}}',
content: {
text: 'The concentration is 100μM',
source: 'discord',
},
},
{
name: '{{name2}}',
content: {
text: 'Processed concentration: 100μM',
actions: ['DETECT_QUANTITATIVE'],
metadata: {
numericData: [{ value: 100, unit: 'μM', type: 'concentration' }],
hasValidData: true,
},
},
},
],
],
},
};
export default quantitativeActions;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment