Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
188 lines
5.0 KiB
TypeScript
188 lines
5.0 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import * as fs from 'fs/promises'
|
|
import * as path from 'path'
|
|
|
|
/**
|
|
* Agent SOUL File API
|
|
*
|
|
* GET - Get SOUL file content
|
|
* PUT - Update SOUL file content
|
|
* GET /history - Get version history
|
|
*/
|
|
|
|
const AGENT_CORE_PATH = process.env.AGENT_CORE_PATH || '/app/agent-core'
|
|
const SOUL_PATH = path.join(AGENT_CORE_PATH, 'soul')
|
|
|
|
interface SoulVersion {
|
|
version: string
|
|
timestamp: string
|
|
content: string
|
|
author: string
|
|
changes: string
|
|
}
|
|
|
|
// Read SOUL file content
|
|
async function readSoulFile(agentId: string): Promise<string | null> {
|
|
const soulFile = `${agentId}.soul.md`
|
|
const soulFilePath = path.join(SOUL_PATH, soulFile)
|
|
|
|
try {
|
|
const content = await fs.readFile(soulFilePath, 'utf-8')
|
|
return content
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
// Get version history from backup directory
|
|
async function getVersionHistory(agentId: string): Promise<SoulVersion[]> {
|
|
const backupDir = path.join(SOUL_PATH, '.backups')
|
|
const versions: SoulVersion[] = []
|
|
|
|
try {
|
|
const files = await fs.readdir(backupDir)
|
|
const agentBackups = files.filter(f => f.startsWith(`${agentId}-`) && f.endsWith('.soul.md'))
|
|
|
|
for (const file of agentBackups.slice(-10)) { // Last 10 versions
|
|
const filePath = path.join(backupDir, file)
|
|
const stats = await fs.stat(filePath)
|
|
const content = await fs.readFile(filePath, 'utf-8')
|
|
|
|
// Extract timestamp from filename
|
|
const match = file.match(/-(\d+)\.soul\.md$/)
|
|
const timestamp = match ? new Date(parseInt(match[1])).toISOString() : stats.mtime.toISOString()
|
|
|
|
versions.push({
|
|
version: file.replace('.soul.md', ''),
|
|
timestamp,
|
|
content,
|
|
author: 'Admin',
|
|
changes: 'Manual update'
|
|
})
|
|
}
|
|
|
|
// Sort by timestamp descending
|
|
versions.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
|
|
} catch {
|
|
// No backup directory or can't read
|
|
}
|
|
|
|
return versions
|
|
}
|
|
|
|
// GET - Get SOUL file content
|
|
export async function GET(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ agentId: string }> }
|
|
) {
|
|
try {
|
|
const { agentId } = await params
|
|
const url = new URL(request.url)
|
|
const includeHistory = url.searchParams.get('history') === 'true'
|
|
|
|
const content = await readSoulFile(agentId)
|
|
if (!content) {
|
|
return NextResponse.json(
|
|
{ error: 'SOUL file not found' },
|
|
{ status: 404 }
|
|
)
|
|
}
|
|
|
|
const soulFile = `${agentId}.soul.md`
|
|
const soulFilePath = path.join(SOUL_PATH, soulFile)
|
|
const stats = await fs.stat(soulFilePath)
|
|
|
|
const response: {
|
|
agentId: string
|
|
soulFile: string
|
|
content: string
|
|
updatedAt: string
|
|
size: number
|
|
history?: SoulVersion[]
|
|
} = {
|
|
agentId,
|
|
soulFile,
|
|
content,
|
|
updatedAt: stats.mtime.toISOString(),
|
|
size: stats.size
|
|
}
|
|
|
|
if (includeHistory) {
|
|
response.history = await getVersionHistory(agentId)
|
|
}
|
|
|
|
return NextResponse.json(response)
|
|
} catch (error) {
|
|
console.error('Error fetching SOUL file:', error)
|
|
return NextResponse.json(
|
|
{ error: error instanceof Error ? error.message : 'Failed to fetch SOUL file' },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|
|
|
|
// PUT - Update SOUL file content
|
|
export async function PUT(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ agentId: string }> }
|
|
) {
|
|
try {
|
|
const { agentId } = await params
|
|
const body = await request.json()
|
|
const { content, author, changeDescription } = body
|
|
|
|
if (!content) {
|
|
return NextResponse.json(
|
|
{ error: 'content is required' },
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
const soulFile = `${agentId}.soul.md`
|
|
const soulFilePath = path.join(SOUL_PATH, soulFile)
|
|
|
|
// Check if file exists
|
|
try {
|
|
await fs.access(soulFilePath)
|
|
} catch {
|
|
return NextResponse.json(
|
|
{ error: 'SOUL file not found' },
|
|
{ status: 404 }
|
|
)
|
|
}
|
|
|
|
// Create backup before updating
|
|
const backupDir = path.join(SOUL_PATH, '.backups')
|
|
const backupPath = path.join(backupDir, `${agentId}-${Date.now()}.soul.md`)
|
|
|
|
try {
|
|
await fs.mkdir(backupDir, { recursive: true })
|
|
const currentContent = await fs.readFile(soulFilePath, 'utf-8')
|
|
await fs.writeFile(backupPath, currentContent, 'utf-8')
|
|
} catch (backupError) {
|
|
console.warn('Failed to create backup:', backupError)
|
|
}
|
|
|
|
// Write new content
|
|
await fs.writeFile(soulFilePath, content, 'utf-8')
|
|
const stats = await fs.stat(soulFilePath)
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: `SOUL file for ${agentId} updated successfully`,
|
|
agentId,
|
|
soulFile,
|
|
updatedAt: stats.mtime.toISOString(),
|
|
size: stats.size,
|
|
author: author || 'Admin',
|
|
changeDescription: changeDescription || 'Manual update'
|
|
})
|
|
} catch (error) {
|
|
console.error('Error updating SOUL file:', error)
|
|
return NextResponse.json(
|
|
{ error: error instanceof Error ? error.message : 'Failed to update SOUL file' },
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
}
|