Files
GoClaw/scripts/create-tables.mjs

174 lines
6.8 KiB
JavaScript

import mysql from 'mysql2/promise';
async function main() {
const conn = await mysql.createConnection(process.env.DATABASE_URL);
const statements = [
// agentAccessControl
`CREATE TABLE IF NOT EXISTS \`agentAccessControl\` (
\`id\` int AUTO_INCREMENT NOT NULL,
\`agentId\` int NOT NULL,
\`tool\` varchar(50) NOT NULL,
\`isAllowed\` boolean DEFAULT true,
\`maxExecutionsPerHour\` int DEFAULT 100,
\`timeoutSeconds\` int DEFAULT 30,
\`allowedPatterns\` json,
\`blockedPatterns\` json,
\`createdAt\` timestamp NOT NULL DEFAULT (now()),
\`updatedAt\` timestamp NOT NULL DEFAULT (now()) ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT \`agentAccessControl_id\` PRIMARY KEY(\`id\`)
)`,
// agentMetrics
`CREATE TABLE IF NOT EXISTS \`agentMetrics\` (
\`id\` int AUTO_INCREMENT NOT NULL,
\`agentId\` int NOT NULL,
\`requestId\` varchar(64) NOT NULL,
\`userMessage\` text,
\`agentResponse\` text,
\`inputTokens\` int DEFAULT 0,
\`outputTokens\` int DEFAULT 0,
\`totalTokens\` int DEFAULT 0,
\`processingTimeMs\` int NOT NULL,
\`status\` enum('success','error','timeout','rate_limited') NOT NULL,
\`errorMessage\` text,
\`toolsCalled\` json,
\`model\` varchar(100),
\`temperature\` decimal(3,2),
\`createdAt\` timestamp NOT NULL DEFAULT (now()),
CONSTRAINT \`agentMetrics_id\` PRIMARY KEY(\`id\`),
CONSTRAINT \`agentMetrics_requestId_unique\` UNIQUE(\`requestId\`)
)`,
// agents — full schema with isSystem and isOrchestrator
`CREATE TABLE IF NOT EXISTS \`agents\` (
\`id\` int AUTO_INCREMENT NOT NULL,
\`userId\` int NOT NULL,
\`name\` varchar(255) NOT NULL,
\`description\` text,
\`role\` varchar(100) NOT NULL,
\`model\` varchar(100) NOT NULL,
\`provider\` varchar(50) NOT NULL,
\`temperature\` decimal(3,2) DEFAULT '0.7',
\`maxTokens\` int DEFAULT 2048,
\`topP\` decimal(3,2) DEFAULT '1.0',
\`frequencyPenalty\` decimal(3,2) DEFAULT '0.0',
\`presencePenalty\` decimal(3,2) DEFAULT '0.0',
\`systemPrompt\` text,
\`allowedTools\` json,
\`allowedDomains\` json,
\`maxRequestsPerHour\` int DEFAULT 100,
\`isActive\` boolean DEFAULT true,
\`isPublic\` boolean DEFAULT false,
\`isSystem\` boolean DEFAULT false,
\`isOrchestrator\` boolean DEFAULT false,
\`tags\` json,
\`metadata\` json,
\`createdAt\` timestamp NOT NULL DEFAULT (now()),
\`updatedAt\` timestamp NOT NULL DEFAULT (now()) ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT \`agents_id\` PRIMARY KEY(\`id\`)
)`,
// toolDefinitions
`CREATE TABLE IF NOT EXISTS \`toolDefinitions\` (
\`id\` int AUTO_INCREMENT NOT NULL,
\`toolId\` varchar(100) NOT NULL,
\`name\` varchar(255) NOT NULL,
\`description\` text NOT NULL,
\`category\` varchar(50) NOT NULL DEFAULT 'custom',
\`dangerous\` boolean DEFAULT false,
\`parameters\` json,
\`implementation\` text NOT NULL,
\`isActive\` boolean DEFAULT true,
\`createdBy\` int,
\`createdAt\` timestamp NOT NULL DEFAULT (now()),
\`updatedAt\` timestamp NOT NULL DEFAULT (now()) ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT \`toolDefinitions_id\` PRIMARY KEY(\`id\`),
CONSTRAINT \`toolDefinitions_toolId_unique\` UNIQUE(\`toolId\`)
)`,
// browserSessions
`CREATE TABLE IF NOT EXISTS \`browserSessions\` (
\`id\` int AUTO_INCREMENT NOT NULL,
\`sessionId\` varchar(64) NOT NULL,
\`agentId\` int NOT NULL,
\`currentUrl\` text,
\`title\` text,
\`status\` enum('active','idle','closed','error') DEFAULT 'idle',
\`screenshotUrl\` text,
\`lastActionAt\` timestamp DEFAULT (now()),
\`createdAt\` timestamp NOT NULL DEFAULT (now()),
\`closedAt\` timestamp,
CONSTRAINT \`browserSessions_id\` PRIMARY KEY(\`id\`),
CONSTRAINT \`browserSessions_sessionId_unique\` UNIQUE(\`sessionId\`)
)`,
// agentHistory — conversation history per agent
`CREATE TABLE IF NOT EXISTS \`agentHistory\` (
\`id\` int AUTO_INCREMENT NOT NULL,
\`agentId\` int NOT NULL,
\`sessionId\` varchar(64),
\`role\` enum('user','assistant','system','tool') NOT NULL,
\`content\` text NOT NULL,
\`toolCalls\` json,
\`metadata\` json,
\`createdAt\` timestamp NOT NULL DEFAULT (now()),
CONSTRAINT \`agentHistory_id\` PRIMARY KEY(\`id\`)
)`,
// Indexes
`CREATE INDEX IF NOT EXISTS \`agentAccessControl_agentId_tool_idx\` ON \`agentAccessControl\` (\`agentId\`,\`tool\`)`,
`CREATE INDEX IF NOT EXISTS \`agentMetrics_agentId_idx\` ON \`agentMetrics\` (\`agentId\`)`,
`CREATE INDEX IF NOT EXISTS \`agentMetrics_createdAt_idx\` ON \`agentMetrics\` (\`createdAt\`)`,
`CREATE INDEX IF NOT EXISTS \`agents_userId_idx\` ON \`agents\` (\`userId\`)`,
`CREATE INDEX IF NOT EXISTS \`agents_model_idx\` ON \`agents\` (\`model\`)`,
`CREATE INDEX IF NOT EXISTS \`browserSessions_agentId_idx\` ON \`browserSessions\` (\`agentId\`)`,
`CREATE INDEX IF NOT EXISTS \`agentHistory_agentId_idx\` ON \`agentHistory\` (\`agentId\`)`,
];
for (const stmt of statements) {
try {
await conn.query(stmt);
const tableName = stmt.match(/TABLE.*?`(\w+)`/)?.[1] || stmt.match(/INDEX.*?ON `(\w+)`/)?.[1] || 'statement';
console.log('✓', tableName);
} catch (e) {
if (e.code === 'ER_DUP_KEYNAME' || e.message.includes('Duplicate key name')) {
console.log('⚠ Index already exists (ok)');
} else if (e.message.includes('already exists')) {
console.log('⚠ Already exists (ok)');
} else {
console.error('✗ Error:', e.message.slice(0, 120));
}
}
}
// ALTER TABLE to add missing columns to existing tables
const alterStatements = [
`ALTER TABLE \`agents\` ADD COLUMN IF NOT EXISTS \`isSystem\` boolean DEFAULT false`,
`ALTER TABLE \`agents\` ADD COLUMN IF NOT EXISTS \`isOrchestrator\` boolean DEFAULT false`,
];
console.log('\n--- Applying ALTER TABLE migrations ---');
for (const stmt of alterStatements) {
try {
await conn.query(stmt);
const col = stmt.match(/ADD COLUMN.*?`(\w+)`/)?.[1] || 'column';
console.log('✓ Added column:', col);
} catch (e) {
if (e.message.includes('Duplicate column name') || e.message.includes('already exists')) {
const col = stmt.match(/ADD COLUMN.*?`(\w+)`/)?.[1] || 'column';
console.log('⚠ Column already exists:', col, '(ok)');
} else {
console.error('✗ ALTER error:', e.message.slice(0, 120));
}
}
}
const [tables] = await conn.query('SHOW TABLES');
console.log('\n✅ All tables:', tables.map(t => Object.values(t)[0]).join(', '));
await conn.end();
}
main().catch(console.error);