@elizaos/plugin-wolfram
Version:
Wolfram Alpha and Wolfram Cloud integration plugin for ElizaOS
1,596 lines (1,571 loc) • 63.5 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var core = require('@elizaos/core');
var zod = require('zod');
// src/index.ts
var wolframEnvSchema = zod.z.object({
// Wolfram Alpha API configuration
WOLFRAM_APP_ID: zod.z.string().min(1).describe("Wolfram Alpha App ID"),
// Optional: Wolfram Cloud configuration for advanced features
WOLFRAM_CLOUD_API_KEY: zod.z.string().optional().describe("Wolfram Cloud API Key for advanced features"),
// Optional: Custom endpoint for Wolfram services
WOLFRAM_API_ENDPOINT: zod.z.string().url().optional().default("https://api.wolframalpha.com/v2"),
// Optional: LLM API endpoint (different host/base than v2 API)
WOLFRAM_LLM_API_ENDPOINT: zod.z.string().url().optional().default("https://www.wolframalpha.com/api/v1/llm-api"),
// Optional: Conversation API endpoint
WOLFRAM_CONVERSATION_ENDPOINT: zod.z.string().url().optional().default("https://www.wolframalpha.com/api/v1/conversation.jsp"),
// Optional: Response format preferences
WOLFRAM_OUTPUT_FORMAT: zod.z.enum(["plaintext", "image", "mathml", "sound", "wav"]).optional().default("plaintext"),
// Optional: Timeout settings
WOLFRAM_TIMEOUT: zod.z.number().min(1e3).max(3e4).optional().default(1e4),
// Optional: Units preference
WOLFRAM_UNITS: zod.z.enum(["metric", "imperial"]).optional().default("metric"),
// Optional: Location for location-based queries
WOLFRAM_LOCATION: zod.z.string().optional().describe('Location for location-based queries (e.g., "New York, NY")'),
// Optional: Scanner types to use
WOLFRAM_SCANNERS: zod.z.string().optional().describe("Comma-separated list of scanner types to use"),
// Optional: Max results per query
WOLFRAM_MAX_RESULTS: zod.z.number().min(1).max(10).optional().default(5)
});
async function validateWolframConfig(runtime) {
try {
const config = {
WOLFRAM_APP_ID: runtime.getSetting("WOLFRAM_APP_ID") || runtime.getSetting("WOLFRAM_ALPHA_APP_ID"),
WOLFRAM_CLOUD_API_KEY: runtime.getSetting("WOLFRAM_CLOUD_API_KEY"),
WOLFRAM_API_ENDPOINT: runtime.getSetting("WOLFRAM_API_ENDPOINT"),
WOLFRAM_LLM_API_ENDPOINT: runtime.getSetting(
"WOLFRAM_LLM_API_ENDPOINT"
),
WOLFRAM_CONVERSATION_ENDPOINT: runtime.getSetting(
"WOLFRAM_CONVERSATION_ENDPOINT"
),
WOLFRAM_OUTPUT_FORMAT: runtime.getSetting("WOLFRAM_OUTPUT_FORMAT"),
WOLFRAM_TIMEOUT: runtime.getSetting("WOLFRAM_TIMEOUT") ? parseInt(runtime.getSetting("WOLFRAM_TIMEOUT"), 10) : void 0,
WOLFRAM_UNITS: runtime.getSetting("WOLFRAM_UNITS"),
WOLFRAM_LOCATION: runtime.getSetting("WOLFRAM_LOCATION"),
WOLFRAM_SCANNERS: runtime.getSetting("WOLFRAM_SCANNERS"),
WOLFRAM_MAX_RESULTS: runtime.getSetting("WOLFRAM_MAX_RESULTS") ? parseInt(runtime.getSetting("WOLFRAM_MAX_RESULTS"), 10) : void 0
};
const cleanConfig = Object.fromEntries(
Object.entries(config).filter(([_, v]) => v !== void 0 && v !== null)
);
return wolframEnvSchema.parse(cleanConfig);
} catch (error) {
if (error instanceof zod.z.ZodError) {
const errorMessages = error.errors.map((err) => `${err.path.join(".")}: ${err.message}`).join("\n");
throw new Error(
`Wolfram configuration validation failed:
${errorMessages}`
);
}
throw error;
}
}
function isWolframConfigured(runtime) {
const appId = runtime.getSetting("WOLFRAM_APP_ID") || runtime.getSetting("WOLFRAM_ALPHA_APP_ID");
return !!appId;
}
// src/types.ts
var WolframAPIEndpoint = /* @__PURE__ */ ((WolframAPIEndpoint2) => {
WolframAPIEndpoint2["QUERY"] = "/query";
WolframAPIEndpoint2["SIMPLE"] = "/simple";
WolframAPIEndpoint2["SHORT"] = "/short";
WolframAPIEndpoint2["SPOKEN"] = "/spoken";
WolframAPIEndpoint2["RESULT"] = "/result";
WolframAPIEndpoint2["LLM"] = "https://www.wolframalpha.com/api/v1/llm-api";
WolframAPIEndpoint2["CONVERSATION"] = "https://www.wolframalpha.com/api/v1/conversation.jsp";
return WolframAPIEndpoint2;
})(WolframAPIEndpoint || {});
// src/service.ts
var WOLFRAM_SERVICE_NAME = "wolfram";
var WolframService = class extends core.Service {
// Cap cache size to avoid unbounded growth
constructor(runtime) {
super();
this.capabilityDescription = "Provides Wolfram Alpha computational knowledge and mathematical problem solving";
// userId -> conversationID
this.CACHE_TTL = 36e5;
// 1 hour in milliseconds
this.MAX_CACHE_ENTRIES = 200;
this.runtime = runtime;
this.cache = /* @__PURE__ */ new Map();
this.conversationCache = /* @__PURE__ */ new Map();
}
async initialize() {
core.logger.log("\u{1F43A} Initializing Wolfram service...");
try {
this.wolframConfig = await validateWolframConfig(this.runtime);
const axios = await import('axios');
this.client = axios.default.create({
baseURL: this.wolframConfig.WOLFRAM_API_ENDPOINT || "https://api.wolframalpha.com/v2",
timeout: this.wolframConfig.WOLFRAM_TIMEOUT || 1e4,
headers: {
"User-Agent": "ElizaOS-Wolfram-Plugin/1.0"
}
});
await this.validateApiKey();
core.logger.log("\u2705 Wolfram service initialized successfully");
} catch (error) {
core.logger.error("Failed to initialize Wolfram service:", error);
throw error;
}
}
/**
* Validates the API key by making a test request
*/
async validateApiKey() {
try {
const response = await this.client.get("/short", {
params: {
appid: this.wolframConfig.WOLFRAM_APP_ID,
input: "2+2"
}
});
if (!response?.data || typeof response.data !== "string") {
throw new Error("Unexpected validation response");
}
} catch (error) {
core.logger.error("Failed to validate Wolfram API key:", error);
throw new Error("Invalid or missing Wolfram Alpha App ID");
}
}
/**
* Lightweight retry for transient errors (429/5xx)
*/
async getWithRetry(client, url, config, maxRetries = 2) {
let attempt = 0;
let delayMs = 250;
while (true) {
try {
return await client.get(url, config);
} catch (err) {
const status = err?.response?.status;
const retriable = status === 429 || status >= 500 && status < 600;
if (!retriable || attempt >= maxRetries) {
throw err;
}
await new Promise((r) => setTimeout(r, delayMs));
attempt += 1;
delayMs *= 2;
}
}
}
/**
* Main query method for full Wolfram Alpha results
*/
async query(input, options = {}) {
const cacheKey = `query:${input}:${JSON.stringify(options)}`;
const cached = this.getCached(cacheKey);
if (cached) {
core.logger.log("\u{1F3AF} Returning cached Wolfram query result");
return cached;
}
try {
core.logger.log(`\u{1F50D} Querying Wolfram Alpha: "${input}"`);
const params = {
input,
appid: this.wolframConfig.WOLFRAM_APP_ID,
format: "plaintext,image",
output: "json",
units: this.wolframConfig.WOLFRAM_UNITS,
...options
};
if (this.wolframConfig.WOLFRAM_LOCATION && !params.location) {
params.location = this.wolframConfig.WOLFRAM_LOCATION;
}
if (this.wolframConfig.WOLFRAM_SCANNERS && !params.scanner) {
params.scanner = this.wolframConfig.WOLFRAM_SCANNERS;
}
const response = await this.getWithRetry(this.client, "/query" /* QUERY */, {
params
});
const result = response.data.queryresult;
if (result.success) {
this.setCached(cacheKey, result);
core.logger.log(`\u2705 Wolfram query successful with ${result.numpods} pods`);
} else {
core.logger.warn(`\u26A0\uFE0F Wolfram query returned no results for: "${input}"`);
}
return result;
} catch (error) {
core.logger.error("\u274C Wolfram query failed:", error);
throw new Error(
`Wolfram query failed: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Simple API - returns a single image result
*/
async getSimpleAnswer(input) {
const cacheKey = `simple:${input}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F5BC}\uFE0F Getting simple answer for: "${input}"`);
const response = await this.getWithRetry(this.client, "/simple" /* SIMPLE */, {
params: {
appid: this.wolframConfig.WOLFRAM_APP_ID,
input,
units: this.wolframConfig.WOLFRAM_UNITS,
location: this.wolframConfig.WOLFRAM_LOCATION
},
responseType: "arraybuffer"
});
const base64 = Buffer.from(response.data).toString("base64");
const imageUrl = `data:image/gif;base64,${base64}`;
this.setCached(cacheKey, imageUrl);
return imageUrl;
} catch (error) {
core.logger.error("Failed to get simple answer:", error);
throw new Error(
`Simple answer failed: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Short Answer API - returns a single plaintext result
*/
async getShortAnswer(input) {
const cacheKey = `short:${input}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F4DD} Getting short answer for: "${input}"`);
const response = await this.getWithRetry(this.client, "/short" /* SHORT */, {
params: {
appid: this.wolframConfig.WOLFRAM_APP_ID,
input,
units: this.wolframConfig.WOLFRAM_UNITS,
location: this.wolframConfig.WOLFRAM_LOCATION
}
});
const result = {
answer: response.data,
success: true
};
this.setCached(cacheKey, result);
return result;
} catch (error) {
core.logger.error("Failed to get short answer:", error);
return {
answer: "",
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Spoken Answer API - returns natural language response
*/
async getSpokenAnswer(input) {
const cacheKey = `spoken:${input}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F5E3}\uFE0F Getting spoken answer for: "${input}"`);
const response = await this.getWithRetry(this.client, "/spoken" /* SPOKEN */, {
params: {
appid: this.wolframConfig.WOLFRAM_APP_ID,
input,
units: this.wolframConfig.WOLFRAM_UNITS,
location: this.wolframConfig.WOLFRAM_LOCATION
}
});
const result = {
spoken: response.data,
success: true
};
this.setCached(cacheKey, result);
return result;
} catch (error) {
core.logger.error("Failed to get spoken answer:", error);
return {
spoken: "",
success: false,
error: error instanceof Error ? error.message : String(error)
};
}
}
/**
* Conversational API - supports multi-turn conversations
*/
async conversationalQuery(input, userId, maxChars = 2e3) {
try {
core.logger.log(`\u{1F4AC} Conversational query from user ${userId}: "${input}"`);
let conversationID = this.conversationCache.get(userId);
const params = {
input,
appid: this.wolframConfig.WOLFRAM_APP_ID,
maxchars: maxChars
};
if (conversationID) {
params.conversationID = conversationID;
}
const llmUrl = this.wolframConfig.WOLFRAM_LLM_API_ENDPOINT || "https://www.wolframalpha.com/api/v1/llm-api" /* LLM */;
const headers = this.wolframConfig.WOLFRAM_CLOUD_API_KEY ? { "X-Wolfram-Cloud-Api-Key": this.wolframConfig.WOLFRAM_CLOUD_API_KEY } : void 0;
const response = await this.getWithRetry(this.client, llmUrl, {
params,
headers
});
const result = response.data;
if (result.conversationID) {
this.conversationCache.set(userId, result.conversationID);
}
core.logger.log(`\u2705 Conversational response received`);
return result;
} catch (error) {
core.logger.error("Error in conversational query:", error);
throw new Error(
`Conversational query failed: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Clear conversation context for a user
*/
clearConversation(userId) {
this.conversationCache.delete(userId);
core.logger.log(`\u{1F504} Cleared conversation for user ${userId}`);
}
/**
* Specialized method for solving mathematical equations
*/
async solveMath(equation) {
const cacheKey = `solve:${equation}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F9EE} Solving equation: "${equation}"`);
const result = await this.query(`solve ${equation}`);
if (!result.success || !result.pods) {
return "Could not solve the equation";
}
const solutionPod = result.pods.find(
(pod) => pod.title === "Solution" || pod.title === "Result" || pod.title.includes("solution")
);
if (solutionPod && solutionPod.subpods && solutionPod.subpods[0]) {
const solution = solutionPod.subpods[0].plaintext || "No solution found";
this.setCached(cacheKey, solution);
return solution;
}
return "No solution found";
} catch (error) {
core.logger.error("Error solving equation:", error);
throw new Error(
`Failed to solve equation: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Get step-by-step solutions for problems
*/
async getStepByStep(problem) {
const cacheKey = `steps:${problem}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F4CB} Getting step-by-step solution for: "${problem}"`);
const result = await this.query(problem, {
podstate: "Step-by-step solution"
});
if (!result.success || !result.pods) {
return ["Could not generate step-by-step solution"];
}
const steps = [];
for (const pod of result.pods) {
if (pod.title.includes("step") || pod.title.includes("Step") || pod.scanner === "Solve") {
for (const subpod of pod.subpods || []) {
if (subpod.plaintext) {
steps.push(subpod.plaintext);
}
}
}
}
if (steps.length === 0) {
for (const pod of result.pods) {
if (pod.subpods) {
for (const subpod of pod.subpods) {
if (subpod.plaintext) {
steps.push(`${pod.title}: ${subpod.plaintext}`);
}
}
}
}
}
this.setCached(cacheKey, steps);
return steps.length > 0 ? steps : ["No step-by-step solution available"];
} catch (error) {
core.logger.error("Error getting step-by-step solution:", error);
throw new Error(
`Failed to get step-by-step solution: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Compute mathematical expressions
*/
async compute(expression) {
const cacheKey = `compute:${expression}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F522} Computing: "${expression}"`);
const shortAnswer = await this.getShortAnswer(expression);
if (shortAnswer.success && shortAnswer.answer) {
this.setCached(cacheKey, shortAnswer.answer);
return shortAnswer.answer;
}
const result = await this.query(expression);
if (result.success && result.pods && result.pods.length > 0) {
const resultPod = result.pods.find(
(pod) => pod.title === "Result" || pod.title === "Value" || pod.title === "Decimal approximation"
);
if (resultPod && resultPod.subpods && resultPod.subpods[0]) {
const answer = resultPod.subpods[0].plaintext || "No result";
this.setCached(cacheKey, answer);
return answer;
}
}
return "Could not compute expression";
} catch (error) {
core.logger.error("Error computing expression:", error);
throw new Error(
`Failed to compute: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Get facts about a topic
*/
async getFacts(topic) {
const cacheKey = `facts:${topic}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F4DA} Getting facts about: "${topic}"`);
const result = await this.query(topic);
if (!result.success || !result.pods) {
return [`No facts found about ${topic}`];
}
const facts = [];
for (const pod of result.pods) {
if (pod.subpods) {
for (const subpod of pod.subpods) {
if (subpod.plaintext && subpod.plaintext.length > 10) {
facts.push(`${pod.title}: ${subpod.plaintext}`);
}
}
}
}
this.setCached(cacheKey, facts);
return facts.length > 0 ? facts : [`No facts found about ${topic}`];
} catch (error) {
core.logger.error("Error getting facts:", error);
throw new Error(
`Failed to get facts: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Analyze data and provide statistical insights
*/
async analyzeData(data) {
const cacheKey = `analyze:${data}`;
const cached = this.getCached(cacheKey);
if (cached) {
return cached;
}
try {
core.logger.log(`\u{1F4CA} Analyzing data: "${data}"`);
const result = await this.query(`statistics ${data}`);
if (!result.success || !result.pods) {
return { input: data, results: {}, error: "Could not analyze data" };
}
const analysis = {
input: data,
results: {}
};
for (const pod of result.pods) {
if (pod.subpods) {
const podData = [];
for (const subpod of pod.subpods) {
if (subpod.plaintext) {
podData.push(subpod.plaintext);
}
}
if (podData.length > 0) {
analysis.results[pod.title] = podData;
}
}
}
this.setCached(cacheKey, analysis);
return analysis;
} catch (error) {
core.logger.error("Error analyzing data:", error);
throw new Error(
`Failed to analyze data: ${error instanceof Error ? error.message : String(error)}`
);
}
}
/**
* Format Wolfram Alpha results for display
*/
formatResult(result) {
if (!result.success) {
return "No results found";
}
const output = [];
if (result.pods) {
const pods = result.pods.filter((p) => p.title !== "Input");
const primaryPods = pods.filter((p) => p.primary);
const podsToRender = primaryPods.length > 0 ? primaryPods : pods;
for (const pod of podsToRender) {
if (!pod.subpods || pod.subpods.length === 0) continue;
output.push(`**${pod.title}**`);
for (const subpod of pod.subpods) {
if (subpod.plaintext) {
output.push(subpod.plaintext);
}
}
}
}
if (result.assumptions) {
output.push("\n*Assumptions:*");
for (const assumption of result.assumptions) {
if (assumption.values) {
output.push(`- ${assumption.values.map((v) => v.desc).join(", ")}`);
}
}
}
if (result.warnings) {
output.push("\n*Warnings:*");
for (const warning of result.warnings) {
output.push(`- ${warning.text}`);
}
}
return output.join("\n") || "No results to display";
}
/**
* Cache management methods
*/
getCached(key) {
const entry = this.cache.get(key);
if (!entry) return null;
if (Date.now() - entry.timestamp > entry.ttl) {
this.cache.delete(key);
return null;
}
return entry.result;
}
setCached(key, result, ttl = this.CACHE_TTL) {
this.cache.set(key, {
query: key,
result,
timestamp: Date.now(),
ttl
});
this.cleanCache();
if (this.cache.size > this.MAX_CACHE_ENTRIES) {
const oldestKey = this.cache.keys().next().value;
if (oldestKey) this.cache.delete(oldestKey);
}
}
cleanCache() {
const now = Date.now();
for (const [key, entry] of this.cache.entries()) {
if (now - entry.timestamp > entry.ttl) {
this.cache.delete(key);
}
}
}
/**
* Clear all caches
*/
clearCache() {
this.cache.clear();
this.conversationCache.clear();
core.logger.log("\u{1F5D1}\uFE0F Wolfram cache cleared");
}
/**
* Get service statistics
*/
getStats() {
return {
cacheSize: this.cache.size,
activeConversations: this.conversationCache.size,
config: {
units: this.wolframConfig.WOLFRAM_UNITS,
location: this.wolframConfig.WOLFRAM_LOCATION,
maxResults: this.wolframConfig.WOLFRAM_MAX_RESULTS
}
};
}
/**
* Stop the service and clean up resources
*/
async stop() {
core.logger.log("\u{1F6D1} Stopping Wolfram service...");
this.clearCache();
core.logger.log("\u2705 Wolfram service stopped");
}
};
WolframService.serviceType = WOLFRAM_SERVICE_NAME;
var queryTemplate = `
You are helping the user with a Wolfram Alpha query.
Recent conversation context:
{{recentMessages}}
The user wants to know: "{{userInput}}"
Extract the query that should be sent to Wolfram Alpha. Make it clear and specific.
Return ONLY the query text, nothing else.
`;
var wolframQueryAction = {
name: "WOLFRAM_QUERY",
description: "Query Wolfram Alpha for comprehensive information about any topic, including mathematics, science, geography, history, and more",
validate: async (runtime, _message) => {
const service = runtime.getService(WOLFRAM_SERVICE_NAME);
return service instanceof WolframService;
},
handler: async (runtime, message, state, _options, callback) => {
try {
const service = runtime.getService(
WOLFRAM_SERVICE_NAME
);
if (!service) {
core.logger.error("Wolfram service not found");
const errorMessage = "Wolfram service is not available. Please check the configuration.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: "Service not available"
};
}
state = state || await runtime.composeState(message);
const queryPrompt = core.composePromptFromState({
state,
template: queryTemplate
});
const queryResult = await runtime.useModel(core.ModelType.TEXT_SMALL, {
prompt: queryPrompt
});
const query = queryResult.trim();
core.logger.log(`\u{1F50D} Wolfram query: "${query}"`);
if (!query) {
const errorMessage = "I couldn't understand your query. Please try rephrasing.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage
};
}
await callback?.({
text: `Searching Wolfram Alpha for: "${query}"...`
});
const result = await service.query(query);
const formattedResult = service.formatResult(result);
await callback?.({
text: formattedResult,
metadata: {
query,
success: result.success,
numpods: result.numpods,
source: "Wolfram Alpha"
}
});
return {
success: true,
text: formattedResult,
values: {
lastWolframQuery: query,
lastQueryTime: Date.now(),
querySuccess: result.success
},
data: {
actionName: "WOLFRAM_QUERY",
query,
result,
formattedResult,
pods: result.pods?.length || 0,
success: result.success,
numpods: result.numpods
}
};
} catch (error) {
core.logger.error("Error executing Wolfram query:", error);
const errorMessage = `Failed to query Wolfram Alpha: ${error instanceof Error ? error.message : String(error)}`;
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: error instanceof Error ? error : new Error(String(error))
};
}
},
examples: [
[
{
name: "{{user1}}",
content: { text: "What is the population of Tokyo?" }
},
{
name: "{{agent}}",
content: {
text: "I'll look up the population of Tokyo for you.",
actions: ["WOLFRAM_QUERY"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "What is the integral of x^2?" }
},
{
name: "{{agent}}",
content: {
text: "Let me calculate the integral of x^2.",
actions: ["WOLFRAM_QUERY"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "What's the weather in New York?" }
},
{
name: "{{agent}}",
content: {
text: "I'll check the current weather in New York.",
actions: ["WOLFRAM_QUERY"]
}
}
]
]
};
var computeTemplate = `
You are helping the user with a mathematical computation using Wolfram Alpha.
Recent conversation context:
{{recentMessages}}
The user wants to compute: "{{userInput}}"
Extract the mathematical expression or calculation that should be computed.
Return ONLY the expression, nothing else. Examples:
- "2 + 2"
- "sqrt(144)"
- "integrate x^2 dx"
- "derivative of sin(x)"
`;
var wolframComputeAction = {
name: "WOLFRAM_COMPUTE",
description: "Perform mathematical computations using Wolfram Alpha, including arithmetic, algebra, calculus, and more",
validate: async (runtime, _message) => {
const service = runtime.getService(WOLFRAM_SERVICE_NAME);
return service instanceof WolframService;
},
handler: async (runtime, message, state, options, callback) => {
try {
const service = runtime.getService(
WOLFRAM_SERVICE_NAME
);
if (!service) {
core.logger.error("Wolfram service not found");
const errorMessage = "Wolfram service is not available. Please check the configuration.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: "Service not available"
};
}
const context = options?.context;
const previousQuery = context?.getPreviousResult?.("WOLFRAM_QUERY");
state = state || await runtime.composeState(message);
const computePrompt = core.composePromptFromState({
state,
template: computeTemplate
});
const expressionResult = await runtime.useModel(core.ModelType.TEXT_SMALL, {
prompt: computePrompt
});
const expression = expressionResult.trim();
core.logger.log(`\u{1F522} Computing: "${expression}"`);
if (!expression) {
const errorMessage = "I couldn't understand the expression to compute. Please provide a valid mathematical expression.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage
};
}
await callback?.({
text: `Computing: "${expression}"...`
});
const result = await service.compute(expression);
await callback?.({
text: `Result: ${result}`,
metadata: {
expression,
result,
source: "Wolfram Alpha"
}
});
return {
success: true,
text: `Result: ${result}`,
values: {
lastComputation: expression,
lastResult: result,
computationTime: Date.now()
},
data: {
actionName: "WOLFRAM_COMPUTE",
expression,
result,
previousQueryData: previousQuery?.data || null
}
};
} catch (error) {
core.logger.error("Error computing expression:", error);
const errorMessage = `Failed to compute: ${error instanceof Error ? error.message : String(error)}`;
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: error instanceof Error ? error : new Error(String(error))
};
}
},
examples: [
[
{
name: "{{user1}}",
content: { text: "Calculate 15% of 250" }
},
{
name: "{{agent}}",
content: {
text: "I'll calculate 15% of 250 for you.",
actions: ["WOLFRAM_COMPUTE"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "What is the square root of 2024?" }
},
{
name: "{{agent}}",
content: {
text: "Let me compute the square root of 2024.",
actions: ["WOLFRAM_COMPUTE"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "Calculate the derivative of x^3 + 2x^2 - 5x + 1" }
},
{
name: "{{agent}}",
content: {
text: "I'll calculate the derivative of that polynomial.",
actions: ["WOLFRAM_COMPUTE"]
}
}
]
]
};
var solveTemplate = `
You are helping the user solve an equation or system of equations using Wolfram Alpha.
Recent conversation context:
{{recentMessages}}
The user wants to solve: "{{userInput}}"
Extract the equation or system that needs to be solved.
Return ONLY the equation(s), nothing else. Examples:
- "2x + 5 = 15"
- "x^2 - 4x + 3 = 0"
- "x + y = 10, x - y = 2"
`;
var wolframSolveAction = {
name: "WOLFRAM_SOLVE",
description: "Solve equations and systems of equations using Wolfram Alpha",
validate: async (runtime, _message) => {
const service = runtime.getService(WOLFRAM_SERVICE_NAME);
return service instanceof WolframService;
},
handler: async (runtime, message, state, options, callback) => {
try {
const service = runtime.getService(
WOLFRAM_SERVICE_NAME
);
if (!service) {
core.logger.error("Wolfram service not found");
const errorMessage = "Wolfram service is not available. Please check the configuration.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: "Service not available"
};
}
const context = options?.context;
const previousCompute = context?.getPreviousResult?.("WOLFRAM_COMPUTE");
state = state || await runtime.composeState(message);
const solvePrompt = core.composePromptFromState({
state,
template: solveTemplate
});
const equationResult = await runtime.useModel(core.ModelType.TEXT_SMALL, {
prompt: solvePrompt
});
const equation = equationResult.trim();
core.logger.log(`\u{1F9EE} Solving: "${equation}"`);
if (!equation) {
const errorMessage = "I couldn't understand the equation to solve. Please provide a valid equation.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage
};
}
await callback?.({
text: `Solving equation: "${equation}"...`
});
const solution = await service.solveMath(equation);
await callback?.({
text: `Solution: ${solution}`,
metadata: {
equation,
solution,
source: "Wolfram Alpha"
}
});
return {
success: true,
text: `Solution: ${solution}`,
values: {
lastEquation: equation,
lastSolution: solution,
solveTime: Date.now()
},
data: {
actionName: "WOLFRAM_SOLVE",
equation,
solution,
previousComputeData: previousCompute?.data || null,
hasSolution: solution !== "No solution found"
}
};
} catch (error) {
core.logger.error("Error solving equation:", error);
const errorMessage = `Failed to solve equation: ${error instanceof Error ? error.message : String(error)}`;
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: error instanceof Error ? error : new Error(String(error))
};
}
},
examples: [
[
{
name: "{{user1}}",
content: { text: "Solve x^2 - 4x + 3 = 0" }
},
{
name: "{{agent}}",
content: {
text: "I'll solve this quadratic equation for you.",
actions: ["WOLFRAM_SOLVE"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "Find x if 3x + 7 = 22" }
},
{
name: "{{agent}}",
content: {
text: "Let me solve for x in this equation.",
actions: ["WOLFRAM_SOLVE"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "Solve the system: x + y = 10 and x - y = 2" }
},
{
name: "{{agent}}",
content: {
text: "I'll solve this system of equations.",
actions: ["WOLFRAM_SOLVE"]
}
}
]
]
};
var stepByStepTemplate = `
You are helping the user get a step-by-step solution using Wolfram Alpha.
Recent conversation context:
{{recentMessages}}
The user wants step-by-step solution for: "{{userInput}}"
Extract the problem that needs step-by-step solution.
Return ONLY the problem statement, nothing else. Examples:
- "solve x^2 - 5x + 6 = 0"
- "integrate sin(x) dx"
- "factor x^3 - 8"
`;
var wolframStepByStepAction = {
name: "WOLFRAM_STEP_BY_STEP",
description: "Get step-by-step solutions for mathematical problems using Wolfram Alpha",
validate: async (runtime, _message) => {
const service = runtime.getService(WOLFRAM_SERVICE_NAME);
return service instanceof WolframService;
},
handler: async (runtime, message, state, options, callback) => {
try {
const service = runtime.getService(
WOLFRAM_SERVICE_NAME
);
if (!service) {
core.logger.error("Wolfram service not found");
const errorMessage = "Wolfram service is not available. Please check the configuration.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: "Service not available"
};
}
const context = options?.context;
const previousSolve = context?.getPreviousResult?.("WOLFRAM_SOLVE");
const previousCompute = context?.getPreviousResult?.("WOLFRAM_COMPUTE");
state = state || await runtime.composeState(message);
const stepPrompt = core.composePromptFromState({
state,
template: stepByStepTemplate
});
const problemResult = await runtime.useModel(core.ModelType.TEXT_SMALL, {
prompt: stepPrompt
});
const problem = problemResult.trim();
core.logger.log(`\u{1F4CB} Getting step-by-step solution for: "${problem}"`);
if (!problem) {
const errorMessage = "I couldn't understand the problem. Please provide a clear problem statement.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage
};
}
await callback?.({
text: `Getting step-by-step solution for: "${problem}"...`
});
const steps = await service.getStepByStep(problem);
const formattedSteps = steps.map((step, index) => `Step ${index + 1}: ${step}`).join("\n");
await callback?.({
text: formattedSteps,
metadata: {
problem,
steps: steps.length,
source: "Wolfram Alpha"
}
});
return {
success: true,
text: formattedSteps,
values: {
lastProblem: problem,
stepsCount: steps.length,
stepByStepTime: Date.now()
},
data: {
actionName: "WOLFRAM_STEP_BY_STEP",
problem,
steps,
stepsCount: steps.length,
formattedSteps,
previousSolveData: previousSolve?.data || null,
previousComputeData: previousCompute?.data || null
}
};
} catch (error) {
core.logger.error("Error getting step-by-step solution:", error);
const errorMessage = `Failed to get step-by-step solution: ${error instanceof Error ? error.message : String(error)}`;
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: error instanceof Error ? error : new Error(String(error))
};
}
},
examples: [
[
{
name: "{{user1}}",
content: { text: "Show me how to solve x^2 - 6x + 8 = 0 step by step" }
},
{
name: "{{agent}}",
content: {
text: "I'll show you the step-by-step solution for this quadratic equation.",
actions: ["WOLFRAM_STEP_BY_STEP"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "How do I integrate x * sin(x) dx?" }
},
{
name: "{{agent}}",
content: {
text: "Let me show you the step-by-step integration process.",
actions: ["WOLFRAM_STEP_BY_STEP"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "Walk me through factoring x^3 - 27" }
},
{
name: "{{agent}}",
content: {
text: "I'll provide step-by-step factorization.",
actions: ["WOLFRAM_STEP_BY_STEP"]
}
}
]
]
};
var getFactsTemplate = `
You are helping the user get facts about a topic using Wolfram Alpha.
Recent conversation context:
{{recentMessages}}
The user wants facts about: "{{userInput}}"
Extract the topic they want facts about.
Return ONLY the topic, nothing else. Examples:
- "Jupiter"
- "Albert Einstein"
- "photosynthesis"
- "World War II"
`;
var wolframGetFactsAction = {
name: "WOLFRAM_GET_FACTS",
description: "Get facts and information about any topic using Wolfram Alpha",
validate: async (runtime, _message) => {
const service = runtime.getService(WOLFRAM_SERVICE_NAME);
return service instanceof WolframService;
},
handler: async (runtime, message, state, options, callback) => {
try {
const service = runtime.getService(
WOLFRAM_SERVICE_NAME
);
if (!service) {
core.logger.error("Wolfram service not found");
const errorMessage = "Wolfram service is not available. Please check the configuration.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: "Service not available"
};
}
const context = options?.context;
const previousQuery = context?.getPreviousResult?.("WOLFRAM_QUERY");
state = state || await runtime.composeState(message);
const factsPrompt = core.composePromptFromState({
state,
template: getFactsTemplate
});
const topicResult = await runtime.useModel(core.ModelType.TEXT_SMALL, {
prompt: factsPrompt
});
const topic = topicResult.trim();
core.logger.log(`\u{1F4DA} Getting facts about: "${topic}"`);
if (!topic) {
const errorMessage = "I couldn't understand the topic. Please specify what you want to learn about.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage
};
}
await callback?.({
text: `Gathering facts about "${topic}"...`
});
const facts = await service.getFacts(topic);
const formattedFacts = facts.join("\n\n");
await callback?.({
text: formattedFacts,
metadata: {
topic,
factsCount: facts.length,
source: "Wolfram Alpha"
}
});
return {
success: true,
text: formattedFacts,
values: {
lastFactsTopic: topic,
factsCount: facts.length,
factsTime: Date.now()
},
data: {
actionName: "WOLFRAM_GET_FACTS",
topic,
facts,
factsCount: facts.length,
formattedFacts,
previousQueryData: previousQuery?.data || null
}
};
} catch (error) {
core.logger.error("Error getting facts:", error);
const errorMessage = `Failed to get facts: ${error instanceof Error ? error.message : String(error)}`;
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: error instanceof Error ? error : new Error(String(error))
};
}
},
examples: [
[
{
name: "{{user1}}",
content: { text: "Tell me facts about Jupiter" }
},
{
name: "{{agent}}",
content: {
text: "I'll get you facts about Jupiter.",
actions: ["WOLFRAM_GET_FACTS"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "What are some facts about Albert Einstein?" }
},
{
name: "{{agent}}",
content: {
text: "Let me find facts about Albert Einstein.",
actions: ["WOLFRAM_GET_FACTS"]
}
}
],
[
{
name: "{{user1}}",
content: { text: "Give me information about the Eiffel Tower" }
},
{
name: "{{agent}}",
content: {
text: "I'll gather facts about the Eiffel Tower.",
actions: ["WOLFRAM_GET_FACTS"]
}
}
]
]
};
var analyzeDataTemplate = `
You are helping the user analyze data using Wolfram Alpha.
Recent conversation context:
{{recentMessages}}
The user wants to analyze: "{{userInput}}"
Extract the data or dataset that needs to be analyzed. This could be:
- A list of numbers (e.g., "1, 2, 3, 4, 5")
- A data description (e.g., "heights: 170cm, 165cm, 180cm, 175cm")
- A statistical query (e.g., "mean of 10, 20, 30, 40")
Return ONLY the data or analysis request, nothing else.
`;
var wolframAnalyzeDataAction = {
name: "WOLFRAM_ANALYZE_DATA",
description: "Analyze data and get statistical insights using Wolfram Alpha",
validate: async (runtime, _message) => {
const service = runtime.getService(WOLFRAM_SERVICE_NAME);
return service instanceof WolframService;
},
handler: async (runtime, message, state, options, callback) => {
try {
const service = runtime.getService(
WOLFRAM_SERVICE_NAME
);
if (!service) {
core.logger.error("Wolfram service not found");
const errorMessage = "Wolfram service is not available. Please check the configuration.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: "Service not available"
};
}
const context = options?.context;
const previousCompute = context?.getPreviousResult?.("WOLFRAM_COMPUTE");
const previousQuery = context?.getPreviousResult?.("WOLFRAM_QUERY");
state = state || await runtime.composeState(message);
const dataPrompt = core.composePromptFromState({
state,
template: analyzeDataTemplate
});
const dataResult = await runtime.useModel(core.ModelType.TEXT_SMALL, {
prompt: dataPrompt
});
const data = dataResult.trim();
core.logger.log(`\u{1F4CA} Analyzing data: "${data}"`);
if (!data) {
const errorMessage = "I couldn't understand the data to analyze. Please provide valid data or a clear description.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage
};
}
await callback?.({
text: `Analyzing data: "${data.substring(0, 50)}${data.length > 50 ? "..." : ""}"`
});
const analysis = await service.analyzeData(data);
let formattedAnalysis = "Data Analysis Results:\n\n";
if (analysis.error) {
formattedAnalysis = `Error: ${analysis.error}`;
} else if (analysis.results) {
for (const [key, value] of Object.entries(analysis.results)) {
formattedAnalysis += `${key}:
${Array.isArray(value) ? value.join("\n") : value}
`;
}
}
await callback?.({
text: formattedAnalysis,
metadata: {
data: data.substring(0, 100),
analysisType: Object.keys(analysis.results || {}),
source: "Wolfram Alpha"
}
});
return {
success: true,
text: formattedAnalysis,
values: {
lastAnalyzedData: data,
analysisTime: Date.now(),
analysisResultsCount: Object.keys(analysis.results || {}).length
},
data: {
actionName: "WOLFRAM_ANALYZE_DATA",
data,
analysis,
formattedAnalysis,
resultsCount: Object.keys(analysis.results || {}).length,
previousComputeData: previousCompute?.data || null,
previousQueryData: previousQuery?.data || null
}
};
} catch (error) {
core.logger.error("Error analyzing data:", error);
const errorMessage = `Failed to analyze data: ${error instanceof Error ? error.message : String(error)}`;
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: error instanceof Error ? error : new Error(String(error))
};
}
},
examples: [
[
{
name: "{{user1}}",
content: { text: "Analyze this data: 12, 15, 18, 22, 25, 28, 31" }
},
{
name: "{{agent}}",
content: {
text: "I'll analyze this dataset for you.",
actions: ["WOLFRAM_ANALYZE_DATA"]
}
}
],
[
{
name: "{{user1}}",
content: {
text: "What's the standard deviation of 100, 105, 110, 115, 120?"
}
},
{
name: "{{agent}}",
content: {
text: "Let me calculate the statistical analysis for this data.",
actions: ["WOLFRAM_ANALYZE_DATA"]
}
}
],
[
{
name: "{{user1}}",
content: {
text: "Find the correlation between (1,2), (2,4), (3,6), (4,8)"
}
},
{
name: "{{agent}}",
content: {
text: "I'll analyze the correlation in this dataset.",
actions: ["WOLFRAM_ANALYZE_DATA"]
}
}
]
]
};
var wolframConversationalAction = {
name: "WOLFRAM_CONVERSATIONAL",
description: "Have a conversational interaction with Wolfram Alpha that maintains context across queries",
validate: async (runtime, _message) => {
const service = runtime.getService(WOLFRAM_SERVICE_NAME);
return service instanceof WolframService;
},
handler: async (runtime, message, _state, options, callback) => {
try {
const service = runtime.getService(
WOLFRAM_SERVICE_NAME
);
if (!service) {
core.logger.error("Wolfram service not found");
const errorMessage = "Wolfram service is not available. Please check the configuration.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: "Service not available"
};
}
const context = options?.context;
const previousConversation = context?.getPreviousResult?.(
"WOLFRAM_CONVERSATIONAL"
);
const previousQuery = context?.getPreviousResult?.("WOLFRAM_QUERY");
const userInput = message.content.text || "";
const userId = message.userId;
if (!userInput) {
const errorMessage = "Please provide a question or topic for discussion.";
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage
};
}
core.logger.log(`\u{1F4AC} Conversational query: "${userInput}"`);
await callback?.({
text: "Processing your question..."
});
const result = await service.conversationalQuery(userInput, userId);
if (result.error) {
const errorMessage = `Conversation error: ${result.error}`;
await callback?.({
text: errorMessage,
error: true
});
return {
success: false,
text: errorMessage,
error: result.error
};
}
const response = result.result || "I couldn't generate a response for that question.";
await callback?.({
text: respon