Sasha LLxprt Tools Integration Guide
Generated: 2025-08-06 UTC
Purpose: Technical guide for integrating LLxprt tool execution into Sasha's architecture
Audience: Developers implementing the LLxprt-based tool system
Overview
This guide explains how to integrate LLxprt's tool execution capabilities into Sasha, enabling structured tool invocation through JSON schemas and handler scripts while maintaining our markdown documentation approach.
Architecture Overview
Integration Points
βββββββββββββββββββββββββββββββββββββββββββββββ
β Sasha Chat Interface β
β (User Natural Language) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β Sasha AI Service β
β (Intent Detection & Context) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β LLxprt Bridge β
β (Tool Orchestration Layer) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β Tool Executor β
β (Handler Invocation & Results) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β Handlers & File System β
β (Shell/Python/JS Execution) β
βββββββββββββββββββββββββββββββββββββββββββββββ
Implementation Steps
Step 1: Enhance LLxprt Bridge
Update services/llxprt-bridge.js to support tool execution:
// Add to LLxprtBridge class
class LLxprtBridge {
// Existing streaming methods...
async executeToolHandler(toolName, parameters) {
const tool = await this.toolRegistry.getTool(toolName);
if (!tool) {
throw new Error(`Tool not found: ${toolName}`);
}
// Check permissions
const permitted = await this.permissionService.checkPermission(
toolName,
this.currentUser,
parameters
);
if (!permitted) {
throw new Error(`Permission denied for tool: ${toolName}`);
}
// Log the operation start
await this.activityLogger.logToolStart(toolName, parameters);
try {
// Execute handler based on type
const result = await this.executeHandler(
tool.handler,
parameters
);
// Log success
await this.activityLogger.logToolComplete(
toolName,
parameters,
result
);
return result;
} catch (error) {
// Log failure
await this.activityLogger.logToolError(
toolName,
parameters,
error
);
throw error;
}
}
async executeHandler(handler, parameters) {
const { type, path } = handler;
switch (type) {
case 'shell':
return this.executeShellHandler(path, parameters);
case 'python':
return this.executePythonHandler(path, parameters);
case 'javascript':
return this.executeJavaScriptHandler(path, parameters);
default:
throw new Error(`Unknown handler type: ${type}`);
}
}
}
Step 2: Create Tool Registry Service
// services/tool-registry.js
class ToolRegistry {
constructor() {
this.tools = new Map();
this.schemasPath = 'tools/schemas';
this.handlersPath = 'tools/handlers';
}
async initialize() {
// Load all tool schemas
const schemaFiles = await fs.readdir(this.schemasPath);
for (const file of schemaFiles) {
if (file.endsWith('.json')) {
const schema = await this.loadSchema(file);
this.registerTool(schema);
}
}
console.log(`β
Loaded ${this.tools.size} tools`);
}
async loadSchema(filename) {
const content = await fs.readFile(
path.join(this.schemasPath, filename),
'utf-8'
);
return JSON.parse(content);
}
registerTool(schema) {
this.tools.set(schema.name, {
...schema,
loaded: Date.now()
});
}
getTool(name) {
return this.tools.get(name);
}
listTools() {
return Array.from(this.tools.values());
}
}
Step 3: Implement Handler Executors
// services/handler-executor.js
const { spawn } = require('child_process');
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
class HandlerExecutor {
async executeShellHandler(scriptPath, parameters) {
// Convert parameters to command line arguments
const args = this.parametersToArgs(parameters);
return new Promise((resolve, reject) => {
const process = spawn('bash', [scriptPath, ...args]);
let output = '';
let error = '';
process.stdout.on('data', (data) => {
output += data.toString();
});
process.stderr.on('data', (data) => {
error += data.toString();
});
process.on('close', (code) => {
if (code === 0) {
resolve({ success: true, output });
} else {
reject(new Error(error || `Process exited with code ${code}`));
}
});
});
}
async executePythonHandler(scriptPath, parameters) {
const args = JSON.stringify(parameters);
const { stdout, stderr } = await exec(
`python3 ${scriptPath} '${args}'`
);
if (stderr) {
throw new Error(stderr);
}
return JSON.parse(stdout);
}
async executeJavaScriptHandler(scriptPath, parameters) {
const args = JSON.stringify(parameters);
const { stdout, stderr } = await exec(
`node ${scriptPath} '${args}'`
);
if (stderr) {
throw new Error(stderr);
}
return JSON.parse(stdout);
}
parametersToArgs(parameters) {
return Object.entries(parameters).flatMap(([key, value]) => {
return [`--${key}`, String(value)];
});
}
}
Tool Definition Examples
Example 1: File Reader Tool
Schema (tools/schemas/read-file.json):
{
"name": "read_file",
"description": "Reads and returns file content",
"parameters": {
"file_path": {
"type": "string",
"description": "Path to the file to read",
"required": true
},
"encoding": {
"type": "string",
"description": "File encoding (default: utf-8)",
"required": false,
"default": "utf-8"
}
},
"handler": {
"type": "shell",
"path": "tools/handlers/read-file.sh"
},
"permissions": {
"riskLevel": "low",
"requiresConfirmation": false,
"category": "utility"
}
}
Handler (tools/handlers/read-file.sh):
#!/bin/bash
FILE_PATH=""
ENCODING="utf-8"
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--file_path)
FILE_PATH="$2"
shift 2
;;
--encoding)
ENCODING="$2"
shift 2
;;
*)
shift
;;
esac
done
# Validate file exists
if [ ! -f "$FILE_PATH" ]; then
echo "{\"success\": false, \"error\": \"File not found\"}" >&2
exit 1
fi
# Read file content
CONTENT=$(cat "$FILE_PATH" 2>/dev/null)
if [ $? -eq 0 ]; then
# Escape JSON special characters
CONTENT=$(echo "$CONTENT" | jq -Rs .)
echo "{\"success\": true, \"content\": $CONTENT}"
else
echo "{\"success\": false, \"error\": \"Failed to read file\"}" >&2
exit 1
fi
Example 2: Document Summarizer Tool
Schema (tools/schemas/summarize-document.json):
{
"name": "summarize_document",
"description": "Summarizes document into bullet points",
"parameters": {
"file_path": {
"type": "string",
"description": "Document to summarize",
"required": true
},
"summary_length": {
"type": "integer",
"description": "Number of bullet points",
"required": false,
"default": 5
}
},
"handler": {
"type": "python",
"path": "tools/handlers/summarize.py"
},
"permissions": {
"riskLevel": "low",
"requiresConfirmation": true,
"category": "enhancement"
}
}
Handler (tools/handlers/summarize.py):
#!/usr/bin/env python3
import sys
import json
def summarize_document(params):
file_path = params['file_path']
summary_length = params.get('summary_length', 5)
try:
with open(file_path, 'r') as f:
content = f.read()
# AI summarization logic here
# For now, return mock summary
summary_points = [
f"Key point {i+1} from the document"
for i in range(summary_length)
]
return {
'success': True,
'summary': summary_points,
'word_count': len(content.split())
}
except Exception as e:
return {
'success': False,
'error': str(e)
}
if __name__ == '__main__':
params = json.loads(sys.argv[1])
result = summarize_document(params)
print(json.dumps(result))
Tool Invocation Flow
1. Natural Language to Tool Detection
// In sasha-ai-service.js
async function detectToolIntent(userMessage) {
// Use AI to detect tool intent
const prompt = `
Analyze this message and determine if it requires a tool:
"${userMessage}"
Available tools:
${toolRegistry.listTools().map(t =>
`- ${t.name}: ${t.description}`
).join('\n')}
Response format:
{
"requires_tool": true/false,
"tool_name": "tool_name_if_applicable",
"parameters": {}
}
`;
const response = await llxprtBridge.streamResponse(prompt);
return JSON.parse(response);
}
2. Tool Execution with Confirmation
async function executeToolWithConfirmation(toolName, parameters, ws) {
const tool = toolRegistry.getTool(toolName);
// Check if confirmation required
if (tool.permissions.requiresConfirmation) {
// Send confirmation request to client
ws.send(JSON.stringify({
type: 'tool_confirmation',
tool: toolName,
parameters,
description: tool.description,
riskLevel: tool.permissions.riskLevel
}));
// Wait for user confirmation
const confirmed = await waitForConfirmation(ws);
if (!confirmed) {
return { cancelled: true };
}
}
// Execute tool
return await llxprtBridge.executeToolHandler(toolName, parameters);
}
Security Considerations
Path Validation
function validatePath(path, allowedPaths) {
const resolved = path.resolve(path);
return allowedPaths.some(allowed =>
resolved.startsWith(path.resolve(allowed))
);
}
Parameter Sanitization
function sanitizeParameters(params, schema) {
const clean = {};
for (const [key, config] of Object.entries(schema.parameters)) {
const value = params[key];
// Type validation
if (config.type === 'string') {
clean[key] = String(value).replace(/[;<>|& Sasha LLxprt Tools Integration Guide
Generated: 2025-08-06 UTC
Purpose: Technical guide for integrating LLxprt tool execution into Sasha's architecture
Audience: Developers implementing the LLxprt-based tool system
Overview
This guide explains how to integrate LLxprt's tool execution capabilities into Sasha, enabling structured tool invocation through JSON schemas and handler scripts while maintaining our markdown documentation approach.
Architecture Overview
Integration Points
βββββββββββββββββββββββββββββββββββββββββββββββ
β Sasha Chat Interface β
β (User Natural Language) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β Sasha AI Service β
β (Intent Detection & Context) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β LLxprt Bridge β
β (Tool Orchestration Layer) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β Tool Executor β
β (Handler Invocation & Results) β
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββββββββββββ
β Handlers & File System β
β (Shell/Python/JS Execution) β
βββββββββββββββββββββββββββββββββββββββββββββββ
Implementation Steps
Step 1: Enhance LLxprt Bridge
Update services/llxprt-bridge.js to support tool execution:
// Add to LLxprtBridge class
class LLxprtBridge {
// Existing streaming methods...
async executeToolHandler(toolName, parameters) {
const tool = await this.toolRegistry.getTool(toolName);
if (!tool) {
throw new Error(`Tool not found: ${toolName}`);
}
// Check permissions
const permitted = await this.permissionService.checkPermission(
toolName,
this.currentUser,
parameters
);
if (!permitted) {
throw new Error(`Permission denied for tool: ${toolName}`);
}
// Log the operation start
await this.activityLogger.logToolStart(toolName, parameters);
try {
// Execute handler based on type
const result = await this.executeHandler(
tool.handler,
parameters
);
// Log success
await this.activityLogger.logToolComplete(
toolName,
parameters,
result
);
return result;
} catch (error) {
// Log failure
await this.activityLogger.logToolError(
toolName,
parameters,
error
);
throw error;
}
}
async executeHandler(handler, parameters) {
const { type, path } = handler;
switch (type) {
case 'shell':
return this.executeShellHandler(path, parameters);
case 'python':
return this.executePythonHandler(path, parameters);
case 'javascript':
return this.executeJavaScriptHandler(path, parameters);
default:
throw new Error(`Unknown handler type: ${type}`);
}
}
}
Step 2: Create Tool Registry Service
// services/tool-registry.js
class ToolRegistry {
constructor() {
this.tools = new Map();
this.schemasPath = 'tools/schemas';
this.handlersPath = 'tools/handlers';
}
async initialize() {
// Load all tool schemas
const schemaFiles = await fs.readdir(this.schemasPath);
for (const file of schemaFiles) {
if (file.endsWith('.json')) {
const schema = await this.loadSchema(file);
this.registerTool(schema);
}
}
console.log(`β
Loaded ${this.tools.size} tools`);
}
async loadSchema(filename) {
const content = await fs.readFile(
path.join(this.schemasPath, filename),
'utf-8'
);
return JSON.parse(content);
}
registerTool(schema) {
this.tools.set(schema.name, {
...schema,
loaded: Date.now()
});
}
getTool(name) {
return this.tools.get(name);
}
listTools() {
return Array.from(this.tools.values());
}
}
Step 3: Implement Handler Executors
// services/handler-executor.js
const { spawn } = require('child_process');
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
class HandlerExecutor {
async executeShellHandler(scriptPath, parameters) {
// Convert parameters to command line arguments
const args = this.parametersToArgs(parameters);
return new Promise((resolve, reject) => {
const process = spawn('bash', [scriptPath, ...args]);
let output = '';
let error = '';
process.stdout.on('data', (data) => {
output += data.toString();
});
process.stderr.on('data', (data) => {
error += data.toString();
});
process.on('close', (code) => {
if (code === 0) {
resolve({ success: true, output });
} else {
reject(new Error(error || `Process exited with code ${code}`));
}
});
});
}
async executePythonHandler(scriptPath, parameters) {
const args = JSON.stringify(parameters);
const { stdout, stderr } = await exec(
`python3 ${scriptPath} '${args}'`
);
if (stderr) {
throw new Error(stderr);
}
return JSON.parse(stdout);
}
async executeJavaScriptHandler(scriptPath, parameters) {
const args = JSON.stringify(parameters);
const { stdout, stderr } = await exec(
`node ${scriptPath} '${args}'`
);
if (stderr) {
throw new Error(stderr);
}
return JSON.parse(stdout);
}
parametersToArgs(parameters) {
return Object.entries(parameters).flatMap(([key, value]) => {
return [`--${key}`, String(value)];
});
}
}
Tool Definition Examples
Example 1: File Reader Tool
Schema (tools/schemas/read-file.json):
{
"name": "read_file",
"description": "Reads and returns file content",
"parameters": {
"file_path": {
"type": "string",
"description": "Path to the file to read",
"required": true
},
"encoding": {
"type": "string",
"description": "File encoding (default: utf-8)",
"required": false,
"default": "utf-8"
}
},
"handler": {
"type": "shell",
"path": "tools/handlers/read-file.sh"
},
"permissions": {
"riskLevel": "low",
"requiresConfirmation": false,
"category": "utility"
}
}
Handler (tools/handlers/read-file.sh):
#!/bin/bash
FILE_PATH=""
ENCODING="utf-8"
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--file_path)
FILE_PATH="$2"
shift 2
;;
--encoding)
ENCODING="$2"
shift 2
;;
*)
shift
;;
esac
done
# Validate file exists
if [ ! -f "$FILE_PATH" ]; then
echo "{\"success\": false, \"error\": \"File not found\"}" >&2
exit 1
fi
# Read file content
CONTENT=$(cat "$FILE_PATH" 2>/dev/null)
if [ $? -eq 0 ]; then
# Escape JSON special characters
CONTENT=$(echo "$CONTENT" | jq -Rs .)
echo "{\"success\": true, \"content\": $CONTENT}"
else
echo "{\"success\": false, \"error\": \"Failed to read file\"}" >&2
exit 1
fi
Example 2: Document Summarizer Tool
Schema (tools/schemas/summarize-document.json):
{
"name": "summarize_document",
"description": "Summarizes document into bullet points",
"parameters": {
"file_path": {
"type": "string",
"description": "Document to summarize",
"required": true
},
"summary_length": {
"type": "integer",
"description": "Number of bullet points",
"required": false,
"default": 5
}
},
"handler": {
"type": "python",
"path": "tools/handlers/summarize.py"
},
"permissions": {
"riskLevel": "low",
"requiresConfirmation": true,
"category": "enhancement"
}
}
Handler (tools/handlers/summarize.py):
#!/usr/bin/env python3
import sys
import json
def summarize_document(params):
file_path = params['file_path']
summary_length = params.get('summary_length', 5)
try:
with open(file_path, 'r') as f:
content = f.read()
# AI summarization logic here
# For now, return mock summary
summary_points = [
f"Key point {i+1} from the document"
for i in range(summary_length)
]
return {
'success': True,
'summary': summary_points,
'word_count': len(content.split())
}
except Exception as e:
return {
'success': False,
'error': str(e)
}
if __name__ == '__main__':
params = json.loads(sys.argv[1])
result = summarize_document(params)
print(json.dumps(result))
Tool Invocation Flow
1. Natural Language to Tool Detection
// In sasha-ai-service.js
async function detectToolIntent(userMessage) {
// Use AI to detect tool intent
const prompt = `
Analyze this message and determine if it requires a tool:
"${userMessage}"
Available tools:
${toolRegistry.listTools().map(t =>
`- ${t.name}: ${t.description}`
).join('\n')}
Response format:
{
"requires_tool": true/false,
"tool_name": "tool_name_if_applicable",
"parameters": {}
}
`;
const response = await llxprtBridge.streamResponse(prompt);
return JSON.parse(response);
}
2. Tool Execution with Confirmation
async function executeToolWithConfirmation(toolName, parameters, ws) {
const tool = toolRegistry.getTool(toolName);
// Check if confirmation required
if (tool.permissions.requiresConfirmation) {
// Send confirmation request to client
ws.send(JSON.stringify({
type: 'tool_confirmation',
tool: toolName,
parameters,
description: tool.description,
riskLevel: tool.permissions.riskLevel
}));
// Wait for user confirmation
const confirmed = await waitForConfirmation(ws);
if (!confirmed) {
return { cancelled: true };
}
}
// Execute tool
return await llxprtBridge.executeToolHandler(toolName, parameters);
}
Security Considerations
Path Validation
function validatePath(path, allowedPaths) {
const resolved = path.resolve(path);
return allowedPaths.some(allowed =>
resolved.startsWith(path.resolve(allowed))
);
}
Parameter Sanitization
]/g, '');
} else if (config.type === 'integer') {
clean[key] = parseInt(value, 10);
} else if (config.type === 'boolean') {
clean[key] = Boolean(value);
}
// Required validation
if (config.required && !clean[key]) {
throw new Error(`Missing required parameter: ${key}`);
}
// Default values
if (!clean[key] && config.default) {
clean[key] = config.default;
}
}
return clean;
}
Monitoring and Logging
Activity Log Integration
class ActivityLogger {
async logToolStart(toolName, parameters) {
await this.log({
timestamp: new Date().toISOString(),
action: 'tool_started',
tool: toolName,
parameters: this.redactSensitive(parameters),
user: this.currentUser,
sessionId: this.sessionId
});
}
async logToolComplete(toolName, parameters, result) {
await this.log({
timestamp: new Date().toISOString(),
action: 'tool_completed',
tool: toolName,
parameters: this.redactSensitive(parameters),
result: this.summarizeResult(result),
user: this.currentUser,
sessionId: this.sessionId
});
}
}
Testing Tools
Tool Test Framework
// test/tool-tester.js
class ToolTester {
async testTool(toolName, testCases) {
const tool = toolRegistry.getTool(toolName);
const results = [];
for (const testCase of testCases) {
try {
const result = await llxprtBridge.executeToolHandler(
toolName,
testCase.input
);
results.push({
name: testCase.name,
passed: this.validateOutput(result, testCase.expected),
result
});
} catch (error) {
results.push({
name: testCase.name,
passed: false,
error: error.message
});
}
}
return results;
}
}
Deployment Checklist
Before Going Live
- All tool schemas validated against JSON schema
- Handler scripts tested with various inputs
- Permission configurations reviewed
- Activity logging confirmed working
- Error handling tested for all handlers
- Rate limiting configured
- Security paths validated
- Confirmation flows tested
- Documentation complete for all tools
- Performance benchmarks meet requirements
Additional Resources
This guide provides the technical foundation for integrating LLxprt's structured tool execution into Sasha while maintaining our user-friendly markdown documentation approach.