refactor: Remove outdated validation and planning documents for agents service

This commit is contained in:
Vaayne 2025-09-18 12:02:11 +08:00
parent 8ada7ffaf6
commit 49eed449c3
5 changed files with 2 additions and 1333 deletions

View File

@ -34,10 +34,10 @@
"*.css": "tailwindcss" "*.css": "tailwindcss"
}, },
"files.eol": "\n", "files.eol": "\n",
// "i18n-ally.displayLanguage": "zh-cn", // "i18n-ally.displayLanguage": "zh-cn",
"i18n-ally.enabledFrameworks": ["react-i18next", "i18next"], "i18n-ally.enabledFrameworks": ["react-i18next", "i18next"],
"i18n-ally.enabledParsers": ["ts", "js", "json"], // "i18n-ally.enabledParsers": ["ts", "js", "json"], //
"i18n-ally.fullReloadOnChanged": true, "i18n-ally.fullReloadOnChanged": true, //
"i18n-ally.keystyle": "nested", // "i18n-ally.keystyle": "nested", //
"i18n-ally.localesPaths": ["src/renderer/src/i18n/locales"], "i18n-ally.localesPaths": ["src/renderer/src/i18n/locales"],
// "i18n-ally.namespace": true, // // "i18n-ally.namespace": true, //

View File

@ -1,238 +0,0 @@
# Agents Service Refactoring - Validation Report
## Overview
This report documents the comprehensive validation of the agents service refactoring completed on September 12, 2025. All tests were performed to ensure the refactored system maintains full functionality while providing improved structure and maintainability.
## Validation Summary
**ALL VALIDATIONS PASSED** - The refactoring has been successfully completed and verified.
---
## 1. Build and Compilation Validation
### Command: `yarn build:check`
**Status:** ✅ PASSED
**Results:**
- TypeScript compilation for Node.js environment: ✅ PASSED
- TypeScript compilation for Web environment: ✅ PASSED
- i18n validation: ✅ PASSED
- Test suite execution: ✅ PASSED (1420 tests across 108 files)
**Duration:** 23.12s
### Key Findings:
- All TypeScript files compile without errors
- No type definition conflicts detected
- Import/export structure is correctly maintained
- All service dependencies resolve correctly
---
## 2. Migration System Validation
### Custom Migration Test
**Status:** ✅ PASSED
**Test Coverage:**
1. ✅ Migration tracking table creation
2. ✅ Migration indexes creation
3. ✅ Migration record insertion/retrieval
4. ✅ Database schema creation (agents table)
5. ✅ Agent record CRUD operations
6. ✅ Session tables creation
7. ✅ Session logs table creation
8. ✅ Foreign key relationships
9. ✅ Data retrieval with joins
10. ✅ Migration cleanup
### Key Findings:
- Migration system initializes correctly
- All migration tables and indexes are created properly
- Transaction support works as expected
- Rollback functionality is available
- Checksum validation ensures migration integrity
---
## 3. Service Initialization Validation
### Custom Service Structure Test
**Status:** ✅ PASSED
**Validated Components:**
1. ✅ All service files are present and accessible
2. ✅ Migration files are properly organized
3. ✅ Query files are correctly structured
4. ✅ Schema files are properly organized
5. ✅ Module export structure is correct
6. ✅ Backward compatibility is maintained
7. ✅ Old db.ts file has been properly removed
8. ✅ TypeScript compilation validated
### File Structure Verification:
```
src/main/services/agents/
├── ✅ BaseService.ts
├── ✅ services/
│ ├── ✅ AgentService.ts
│ ├── ✅ SessionService.ts
│ ├── ✅ SessionLogService.ts
│ └── ✅ index.ts
├── ✅ database/
│ ├── ✅ migrations/
│ │ ├── ✅ 001_initial_schema.ts
│ │ ├── ✅ 002_add_session_tables.ts
│ │ ├── ✅ types.ts
│ │ └── ✅ index.ts
│ ├── ✅ queries/
│ │ ├── ✅ agent.queries.ts
│ │ ├── ✅ session.queries.ts
│ │ ├── ✅ sessionLog.queries.ts
│ │ └── ✅ index.ts
│ ├── ✅ schema/
│ │ ├── ✅ tables.ts
│ │ ├── ✅ indexes.ts
│ │ ├── ✅ migrations.ts
│ │ └── ✅ index.ts
│ ├── ✅ migrator.ts
│ └── ✅ index.ts
└── ✅ index.ts
```
---
## 4. Database Operations Validation
### Comprehensive CRUD Operations Test
**Status:** ✅ PASSED
**Test Scenarios:**
1. ✅ Database schema setup (tables + indexes)
2. ✅ Agent CRUD operations
- Create: ✅ Agent creation with JSON field serialization
- Read: ✅ Agent retrieval and data integrity verification
- Update: ✅ Agent updates with field validation
- Delete: ✅ Agent deletion (tested via cascade)
- List: ✅ Agent listing and counting operations
3. ✅ Session operations
- Create: ✅ Session creation with foreign key constraints
- Read: ✅ Session retrieval and agent association
- List: ✅ Sessions by agent queries
4. ✅ Session Log operations
- Create: ✅ Multiple log types creation
- Read: ✅ Log retrieval ordered by timestamp
5. ✅ Foreign Key constraints
- Cascade Delete: ✅ Agent deletion cascades to sessions and logs
- Referential Integrity: ✅ Foreign key relationships maintained
6. ✅ Concurrent operations
- Parallel Creation: ✅ 5 concurrent agents created successfully
- Data Integrity: ✅ All concurrent operations verified
### Performance Metrics:
- Agent CRUD operations: < 50ms per operation
- Migration system: < 100ms initialization
- Concurrent operations: Successfully handled 5 parallel operations
---
## 5. Backward Compatibility Validation
### Compatibility Checks:
- ✅ Export structure maintains backward compatibility
- ✅ Legacy query exports available via `AgentQueries_Legacy`
- ✅ Service singleton instances preserved
- ✅ Database interface unchanged for external consumers
- ✅ Migration system added without breaking existing functionality
---
## 6. Code Quality and Structure
### Improvements Delivered:
1. **Modular Organization**: ✅ Services split into focused, single-responsibility files
2. **Migration System**: ✅ Version-controlled schema changes with rollback support
3. **Query Organization**: ✅ SQL queries organized by entity type
4. **Schema Management**: ✅ Table and index definitions centralized
5. **Type Safety**: ✅ TypeScript interfaces for all operations
6. **Error Handling**: ✅ Comprehensive error handling and logging
7. **Testing**: ✅ All existing tests continue to pass
### Benefits Realized:
- **Maintainability**: Easier to locate and modify specific functionality
- **Scalability**: Simple to add new entities without affecting existing code
- **Production Readiness**: Atomic migrations with transaction support
- **Team Development**: Reduced merge conflicts with smaller, focused files
- **Documentation**: Clear structure makes codebase more navigable
---
## 7. Security and Safety Validation
### Security Measures Verified:
- ✅ SQL injection protection via parameterized queries
- ✅ Transaction isolation for atomic operations
- ✅ Foreign key constraints prevent orphaned records
- ✅ JSON field validation and safe parsing
- ✅ Migration checksums prevent tampering
---
## 8. Performance Validation
### Database Operations:
- ✅ Index utilization verified for common queries
- ✅ Foreign key constraints optimized with indexes
- ✅ JSON field operations efficient
- ✅ Concurrent access handled properly
---
## Cleanup
The following temporary test files were created for validation and can be safely removed:
- `/Users/weliu/workspace/cherry-studio/migration-validation-test.js`
- `/Users/weliu/workspace/cherry-studio/service-initialization-test.js`
- `/Users/weliu/workspace/cherry-studio/database-operations-test.js`
---
## Final Recommendation
✅ **APPROVED FOR PRODUCTION**
The agents service refactoring has been successfully completed and thoroughly validated. All functionality is preserved while delivering significant improvements in code organization, maintainability, and scalability. The migration system is production-ready and will support future schema evolution safely.
## Next Steps
1. The refactoring is complete and ready for deployment
2. Consider removing temporary test files
3. Monitor the system in production to validate real-world performance
4. Begin utilizing the new modular structure for future feature development
---
**Validation completed:** September 12, 2025
**Total validation time:** ~45 minutes
**Tests executed:** 1420 + custom validation tests
**Overall result:** ✅ SUCCESS

View File

@ -1,198 +0,0 @@
# Agents Service Refactoring Plan
## Overview
Restructure the agents service to split database operations into smaller, more manageable files with migration support.
## New Folder Structure
```
src/main/services/agents/
├── database/
│ ├── migrations/
│ │ ├── types.ts # Migration interfaces
│ │ ├── 001_initial_schema.ts # Initial tables & indexes
│ │ ├── 002_add_session_tables.ts # Session related tables
│ │ └── index.ts # Export all migrations
│ ├── queries/
│ │ ├── agent.queries.ts # Agent CRUD queries
│ │ ├── session.queries.ts # Session CRUD queries
│ │ ├── sessionLog.queries.ts # Session log queries
│ │ └── index.ts # Export all queries
│ ├── schema/
│ │ ├── tables.ts # Table definitions
│ │ ├── indexes.ts # Index definitions
│ │ ├── migrations.ts # Migration tracking table
│ │ └── index.ts # Export all schema
│ ├── migrator.ts # Migration runner class
│ └── index.ts # Main database exports
├── services/
│ ├── AgentService.ts # Agent business logic
│ ├── SessionService.ts # Session business logic
│ ├── SessionLogService.ts # Session log business logic
│ └── index.ts # Export all services
├── BaseService.ts # Shared database utilities with migration support
└── index.ts # Main module exports
```
## Implementation Tasks
### Task 1: Create Folder Structure and Migration System Infrastructure
**Status**: ✅ COMPLETED
**Agent**: `general-purpose`
**Description**: Create all necessary directories and implement the migration system infrastructure
**Subtasks**:
- [x] Create database/, database/migrations/, database/queries/, database/schema/, services/ directories
- [x] Implement migration types and interfaces in database/migrations/types.ts
- [x] Build Migrator class with transaction support in database/migrator.ts
- [x] Create migration tracking table schema in database/schema/migrations.ts
---
### Task 2: Split Database Queries from db.ts
**Status**: ✅ COMPLETED
**Agent**: `general-purpose`
**Description**: Extract and organize queries from the current db.ts file into separate, focused files
**Subtasks**:
- [x] Move agent queries to database/queries/agent.queries.ts
- [x] Move session queries to database/queries/session.queries.ts
- [x] Move session log queries to database/queries/sessionLog.queries.ts
- [x] Extract table definitions to database/schema/tables.ts
- [x] Extract index definitions to database/schema/indexes.ts
- [x] Create index files for queries and schema directories
- [x] Update db.ts to maintain backward compatibility by re-exporting split queries
---
### Task 3: Create Initial Migration Files
**Status**: ✅ COMPLETED
**Agent**: `general-purpose`
**Description**: Create migration files based on existing schema
**Subtasks**:
- [x] Create 001_initial_schema.ts with agents table and indexes
- [x] Create 002_add_session_tables.ts with sessions and session_logs tables
- [x] Create database/migrations/index.ts to export all migrations
---
### Task 4: Update BaseService with Migration Support
**Status**: ✅ COMPLETED
**Agent**: `general-purpose`
**Description**: Integrate migration system into BaseService initialization
**Subtasks**:
- [x] Update BaseService.ts to use Migrator on initialize
- [x] Keep existing JSON serialization utilities
- [x] Update database initialization flow
---
### Task 5: Reorganize Service Files
**Status**: ✅ COMPLETED
**Agent**: `general-purpose`
**Description**: Move service files to services subdirectory and update imports
**Subtasks**:
- [x] Move AgentService.ts to services/
- [x] Move SessionService.ts to services/
- [x] Move SessionLogService.ts to services/
- [x] Update import paths in all service files (now import from '../BaseService' and '../db')
- [x] Create services/index.ts to export all services
---
### Task 6: Create Export Structure and Clean Up
**Status**: ✅ COMPLETED
**Agent**: `general-purpose`
**Description**: Create proper export hierarchy and clean up old files
**Subtasks**:
- [x] Create main agents/index.ts with clean exports
- [x] Create database/index.ts for database exports
- [x] Ensure backward compatibility for existing imports
- [x] Remove old db.ts file
- [x] Update any external imports if needed
---
### Task 7: Test and Validate Refactoring
**Status**: ✅ COMPLETED
**Agent**: `general-purpose`
**Description**: Ensure all functionality works after refactoring
**Subtasks**:
- [x] Run build check: `yarn build:check` ✅ PASSED (1420 tests, TypeScript compilation successful)
- [x] Run tests: `yarn test` ✅ PASSED (All existing tests continue to pass)
- [x] Validate migration system works ✅ PASSED (11 migration tests, transaction support verified)
- [x] Check that all services initialize correctly ✅ PASSED (File structure, exports, backward compatibility)
- [x] Verify database operations work as expected ✅ PASSED (CRUD operations, foreign keys, concurrent operations)
**Additional Validation**:
- [x] Created comprehensive validation report (VALIDATION_REPORT.md)
- [x] Validated migration system with custom test suite
- [x] Verified service initialization and file structure
- [x] Tested complete database operations including concurrent access
- [x] Confirmed backward compatibility maintained
- [x] Validated security measures and performance optimizations
---
## Benefits of This Refactoring
1. **Single Responsibility**: Each file handles one specific concern
2. **Version-Controlled Schema**: Migration system tracks all database changes
3. **Easier Maintenance**: Find and modify queries for specific entities quickly
4. **Better Scalability**: Easy to add new entities without cluttering existing files
5. **Clear Organization**: Logical grouping makes navigation intuitive
6. **Production Ready**: Atomic migrations with transaction support
7. **Reduced Merge Conflicts**: Smaller files mean fewer conflicts in team development
## Migration Best Practices Implemented
- ✅ Version-controlled migrations with tracking table
- ✅ Atomic operations with transaction support
- ✅ Rollback capability (optional down migrations)
- ✅ Incremental updates (only run pending migrations)
- ✅ Safe for production deployments
---
**Progress Summary**: 7/7 tasks completed 🎉
**Status**: ✅ **REFACTORING COMPLETED SUCCESSFULLY**
All tasks have been completed and thoroughly validated. The agents service refactoring delivers:
- ✅ Modular, maintainable code structure
- ✅ Production-ready migration system
- ✅ Complete backward compatibility
- ✅ Comprehensive test validation
- ✅ Enhanced developer experience
**Final deliverables:**
- 📁 Reorganized service architecture with clear separation of concerns
- 🗃️ Database migration system with transaction support and rollback capability
- 📋 Comprehensive validation report (VALIDATION_REPORT.md)
- ✅ All 1420+ tests passing with full TypeScript compliance
- 🔒 Security hardening with parameterized queries and foreign key constraints
**Ready for production deployment** 🚀

View File

@ -1,654 +0,0 @@
# Agent API UI Integration Guide
## Overview
This document provides comprehensive guidance for UI components to integrate with the new Agent API system. The agents data is now stored in the database and accessed through API endpoints instead of Redux state management.
## Key Changes from Previous Implementation
### Data Storage
- **Before**: Agent data stored in Redux store
- **After**: Agent data stored in SQLite database, accessed via REST API
### State Management
- **Before**: Redux actions and selectors for agent operations
- **After**: Direct API calls using fetch/axios, no Redux dependency
### Data Flow
- **Before**: Component → Redux Action → State Update → Component Re-render
- **After**: Component → API Call → UI Update → Database
## API Endpoints Overview
### Base Configuration
- **Base URL**: `http://localhost:23333/v1`
- **Authentication**: Bearer token (API key format: `cs-sk-{uuid}`)
- **Content-Type**: `application/json`
### Agent Management (`/agents`)
| Method | Endpoint | Description | Request Body | Response |
|--------|----------|-------------|--------------|----------|
| POST | `/agents` | Create new agent | `CreateAgentRequest` | `AgentEntity` |
| GET | `/agents` | List agents (paginated) | Query params | `{ data: AgentEntity[], total: number }` |
| GET | `/agents/{id}` | Get specific agent | - | `AgentEntity` |
| PUT | `/agents/{id}` | Replace agent (complete update) | `UpdateAgentRequest` | `AgentEntity` |
| PATCH | `/agents/{id}` | Partially update agent | `Partial<UpdateAgentRequest>` | `AgentEntity` |
| DELETE | `/agents/{id}` | Delete agent | - | `204 No Content` |
### Session Management (`/agents/{agentId}/sessions`)
| Method | Endpoint | Description | Request Body | Response |
|--------|----------|-------------|--------------|----------|
| POST | `/agents/{agentId}/sessions` | Create session | `CreateSessionRequest` | `AgentSessionEntity` |
| GET | `/agents/{agentId}/sessions` | List agent sessions | Query params | `{ data: AgentSessionEntity[], total: number }` |
| GET | `/agents/{agentId}/sessions/{id}` | Get specific session | - | `AgentSessionEntity` |
| PUT | `/agents/{agentId}/sessions/{id}` | Replace session (complete update) | `UpdateSessionRequest` | `AgentSessionEntity` |
| PATCH | `/agents/{agentId}/sessions/{id}` | Partially update session | `Partial<UpdateSessionRequest>` | `AgentSessionEntity` |
| DELETE | `/agents/{agentId}/sessions/{id}` | Delete session | - | `204 No Content` |
### Message Streaming (`/agents/{agentId}/sessions/{sessionId}/messages`)
| Method | Endpoint | Description | Request Body | Response |
|--------|----------|-------------|--------------|----------|
| POST | `/agents/{agentId}/sessions/{sessionId}/messages` | Send message to agent | `CreateMessageRequest` | **Stream Response** |
| GET | `/agents/{agentId}/sessions/{sessionId}/messages` | List session messages | Query params | `{ data: SessionMessageEntity[], total: number }` |
## HTTP Methods: PUT vs PATCH
Both agents and sessions support two types of update operations:
### PUT - Complete Replacement
- **Purpose**: Replaces the entire resource with the provided data
- **Behavior**: All fields in the request body will be applied to the resource
- **Use Case**: When you want to completely update a resource with a new set of values
- **Example**: Updating an agent's configuration completely
```typescript
// PUT - Replace entire agent
await fetch('/v1/agents/agent-123', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'New Agent Name',
model: 'gpt-4',
instructions: 'New instructions',
built_in_tools: ['search', 'calculator'],
// All other fields will be reset to defaults if not provided
})
})
```
### PATCH - Partial Update
- **Purpose**: Updates only the specified fields, leaving others unchanged
- **Behavior**: Only the fields present in the request body will be modified
- **Use Case**: When you want to update specific fields without affecting others
- **Example**: Updating only an agent's name or instructions
```typescript
// PATCH - Update only specific fields
await fetch('/v1/agents/agent-123', {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'Updated Agent Name'
// All other fields remain unchanged
})
})
```
### Validation
Both methods use the same validation rules:
- All fields are optional for both PUT and PATCH
- When provided, fields must meet their validation criteria (e.g., `name` cannot be empty)
- The same middleware (`validateAgentUpdate` for agents, `validateSessionUpdate` for sessions) handles both operations
## Data Types & Schemas
### AgentEntity
```typescript
interface AgentEntity {
id: string
type: AgentType
name: string
description?: string
avatar?: string
instructions?: string
// Core configuration
model: string // Required - main model ID
plan_model?: string
small_model?: string
built_in_tools?: string[]
mcps?: string[]
knowledges?: string[]
configuration?: Record<string, any>
accessible_paths?: string[]
permission_mode?: PermissionMode
max_steps?: number
// Timestamps
created_at: string
updated_at: string
}
```
### AgentSessionEntity
```typescript
interface AgentSessionEntity {
id: string
name?: string
main_agent_id: string
sub_agent_ids?: string[]
user_goal?: string
status: SessionStatus
external_session_id?: string
// Configuration overrides (inherits from agent if not specified)
model?: string
plan_model?: string
small_model?: string
built_in_tools?: string[]
mcps?: string[]
knowledges?: string[]
configuration?: Record<string, any>
accessible_paths?: string[]
permission_mode?: PermissionMode
max_steps?: number
// Timestamps
created_at: string
updated_at: string
}
```
### SessionMessageEntity
```typescript
interface SessionMessageEntity {
id: number
session_id: string
parent_id?: number
role: SessionMessageRole // 'user' | 'agent' | 'system' | 'tool'
type: SessionMessageType
content: Record<string, any>
metadata?: Record<string, any>
created_at: string
updated_at: string
}
```
## Creating Agents
### Minimal Agent Creation
For early stage implementation, only use these essential fields:
```typescript
const createAgentRequest = {
name: string, // Required
model: string, // Required
instructions?: string, // System prompt
built_in_tools?: string[],
mcps?: string[],
knowledges?: string[]
}
```
### Example: Create Agent
```typescript
async function createAgent(agentData: CreateAgentRequest): Promise<AgentEntity> {
const response = await fetch('/v1/agents', {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(agentData)
})
if (!response.ok) {
throw new Error(`Agent creation failed: ${response.statusText}`)
}
return await response.json()
}
```
### Example: List Agents
```typescript
async function listAgents(limit = 20, offset = 0): Promise<{data: AgentEntity[], total: number}> {
const response = await fetch(`/v1/agents?limit=${limit}&offset=${offset}`, {
headers: {
'Authorization': `Bearer ${apiKey}`
}
})
return await response.json()
}
```
## Managing Agent Sessions
### Session Creation
```typescript
async function createSession(agentId: string, sessionData: CreateSessionRequest): Promise<AgentSessionEntity> {
const response = await fetch(`/v1/agents/${agentId}/sessions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
user_goal: sessionData.user_goal, // User's goal as input message
model: sessionData.model, // Override agent's model if needed
// tools and mcps can be overridden per session
})
})
return await response.json()
}
```
### Session Updates
Sessions can be updated using either PUT (complete replacement) or PATCH (partial update):
#### Complete Session Replacement (PUT)
```typescript
async function replaceSession(agentId: string, sessionId: string, sessionData: UpdateSessionRequest): Promise<AgentSessionEntity> {
const response = await fetch(`/v1/agents/${agentId}/sessions/${sessionId}`, {
method: 'PUT',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(sessionData) // Complete session configuration
})
return await response.json()
}
```
#### Partial Session Update (PATCH)
```typescript
async function updateSession(agentId: string, sessionId: string, updates: Partial<UpdateSessionRequest>): Promise<AgentSessionEntity> {
const response = await fetch(`/v1/agents/${agentId}/sessions/${sessionId}`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates) // Only the fields to update
})
return await response.json()
}
```
#### Session Status Management
Sessions have five possible statuses:
- `idle`: Ready to process messages
- `running`: Currently processing
- `completed`: Task finished successfully
- `failed`: Encountered an error
- `stopped`: Manually stopped by user
```typescript
// Update only the session status using PATCH
async function updateSessionStatus(agentId: string, sessionId: string, status: SessionStatus): Promise<AgentSessionEntity> {
return await updateSession(agentId, sessionId, { status })
}
```
## Message Streaming Integration
### Sending Messages to Agents
The core interaction point is the message endpoint that accepts user messages and returns streamed responses:
```typescript
async function sendMessageToAgent(
agentId: string,
sessionId: string,
message: CreateMessageRequest
): Promise<ReadableStream> {
const response = await fetch(`/v1/agents/${agentId}/sessions/${sessionId}/messages`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
role: 'user',
type: 'message',
content: {
text: message.text,
// Include any additional context
}
})
})
return response.body // Returns AI SDK streamText compatible stream
}
```
### Processing Streamed Responses
The response follows AI SDK's `streamText` format:
```typescript
async function handleAgentResponse(stream: ReadableStream) {
const reader = stream.getReader()
const decoder = new TextDecoder()
try {
while (true) {
const { done, value } = await reader.read()
if (done) break
const chunk = decoder.decode(value)
const lines = chunk.split('\n')
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6)
if (data === '[DONE]') {
return // Stream completed
}
try {
const parsed = JSON.parse(data)
// Handle different stream events
switch (parsed.type) {
case 'text-delta':
updateUI(parsed.textDelta)
break
case 'tool-call':
handleToolCall(parsed.toolCall)
break
case 'tool-result':
handleToolResult(parsed.toolResult)
break
case 'finish':
handleFinish(parsed.finishReason)
break
}
} catch (parseError) {
console.error('Failed to parse stream data:', parseError)
}
}
}
}
} finally {
reader.releaseLock()
}
}
```
## UI Component Integration Patterns
### Agent List Component
```typescript
function AgentList() {
const [agents, setAgents] = useState<AgentEntity[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
async function loadAgents() {
try {
const result = await listAgents()
setAgents(result.data)
} catch (error) {
console.error('Failed to load agents:', error)
} finally {
setLoading(false)
}
}
loadAgents()
}, [])
const handleDeleteAgent = async (agentId: string) => {
try {
await fetch(`/v1/agents/${agentId}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${apiKey}` }
})
setAgents(agents.filter(agent => agent.id !== agentId))
} catch (error) {
console.error('Failed to delete agent:', error)
}
}
if (loading) return <div>Loading...</div>
return (
<div>
{agents.map(agent => (
<AgentItem
key={agent.id}
agent={agent}
onDelete={() => handleDeleteAgent(agent.id)}
/>
))}
</div>
)
}
```
### Agent Chat Component
```typescript
function AgentChat({ agentId }: { agentId: string }) {
const [session, setSession] = useState<AgentSessionEntity | null>(null)
const [messages, setMessages] = useState<SessionMessageEntity[]>([])
const [inputMessage, setInputMessage] = useState('')
const [isStreaming, setIsStreaming] = useState(false)
// Create session on component mount
useEffect(() => {
async function initSession() {
try {
const newSession = await createSession(agentId, {
user_goal: "General conversation"
})
setSession(newSession)
// Load existing messages
const messagesResult = await fetch(`/v1/agents/${agentId}/sessions/${newSession.id}/messages`, {
headers: { 'Authorization': `Bearer ${apiKey}` }
}).then(r => r.json())
setMessages(messagesResult.data)
} catch (error) {
console.error('Failed to initialize session:', error)
}
}
initSession()
}, [agentId])
const sendMessage = async () => {
if (!session || !inputMessage.trim() || isStreaming) return
setIsStreaming(true)
try {
// Add user message to UI
const userMessage = {
role: 'user' as const,
content: { text: inputMessage },
created_at: new Date().toISOString()
}
setMessages(prev => [...prev, userMessage as any])
setInputMessage('')
// Send to agent and handle streaming response
const stream = await sendMessageToAgent(agentId, session.id, {
text: inputMessage
})
let agentResponse = ''
await handleAgentResponse(stream, (delta: string) => {
agentResponse += delta
// Update UI with streaming text
setMessages(prev => {
const last = prev[prev.length - 1]
if (last?.role === 'agent') {
return [...prev.slice(0, -1), { ...last, content: { text: agentResponse } }]
} else {
return [...prev, {
role: 'agent',
content: { text: agentResponse },
created_at: new Date().toISOString()
} as any]
}
})
})
} catch (error) {
console.error('Failed to send message:', error)
} finally {
setIsStreaming(false)
}
}
return (
<div className="agent-chat">
<div className="messages">
{messages.map((message, index) => (
<div key={index} className={`message ${message.role}`}>
<div className="content">{message.content.text}</div>
</div>
))}
</div>
<div className="input-area">
<input
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
disabled={isStreaming}
placeholder="Type your message..."
/>
<button onClick={sendMessage} disabled={isStreaming || !inputMessage.trim()}>
{isStreaming ? 'Sending...' : 'Send'}
</button>
</div>
</div>
)
}
```
## Error Handling
### API Error Response Format
```typescript
interface ApiError {
error: {
message: string
type: 'validation_error' | 'not_found' | 'internal_error' | 'authentication_error'
code?: string
details?: any[]
}
}
```
### Error Handling Pattern
```typescript
async function apiRequest<T>(url: string, options: RequestInit = {}): Promise<T> {
try {
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
...options.headers
}
})
if (!response.ok) {
const error: ApiError = await response.json()
throw new Error(`${error.error.type}: ${error.error.message}`)
}
return await response.json()
} catch (error) {
console.error('API request failed:', error)
throw error
}
}
```
## Best Practices
### 1. Agent Configuration
- **Minimal Setup**: Start with just `name`, `model`, and `instructions`
- **Gradual Enhancement**: Add `tools`, `mcps`, and `knowledges` as needed
- **Configuration Inheritance**: Sessions inherit agent settings but can override them
### 2. Session Management
- **Single Goal Per Session**: Each session should have one clear `user_goal`
- **Status Tracking**: Always update session status appropriately
- **Resource Cleanup**: Delete completed/failed sessions to manage storage
### 3. Message Streaming
- **Progressive Enhancement**: Show streaming text immediately for better UX
- **Error Recovery**: Handle stream interruptions gracefully
- **Tool Visualization**: Display tool calls and results appropriately
### 4. Performance Considerations
- **Pagination**: Always use `limit` and `offset` for large lists
- **Caching**: Consider caching agent lists locally
- **Debouncing**: Debounce API calls for real-time updates
### 5. User Experience
- **Loading States**: Show loading indicators during API calls
- **Error Messages**: Display user-friendly error messages
- **Optimistic Updates**: Update UI immediately, rollback on errors
## Migration from Redux Implementation
### Step 1: Remove Redux Dependencies
```typescript
// Before
import { useSelector, useDispatch } from 'react-redux'
import { createAgent, listAgents } from '../store/agents'
// After
import { apiRequest } from '../services/api'
```
### Step 2: Replace Redux Hooks
```typescript
// Before
const agents = useSelector(state => state.agents.list)
const dispatch = useDispatch()
// After
const [agents, setAgents] = useState<AgentEntity[]>([])
```
### Step 3: Replace Action Dispatches
```typescript
// Before
dispatch(createAgent(agentData))
// After
const newAgent = await apiRequest<AgentEntity>('/v1/agents', {
method: 'POST',
body: JSON.stringify(agentData)
})
setAgents(prev => [...prev, newAgent])
```
## Conclusion
This new API-based approach provides:
- **Better Performance**: Database storage with efficient queries
- **Real-time Streaming**: AI SDK compatible message streaming
- **Scalability**: Proper pagination and resource management
- **Flexibility**: Session-level configuration overrides
- **Reliability**: Proper error handling and status management
The migration from Redux to direct API integration simplifies the data flow and provides better control over agent interactions.

241
plan.md
View File

@ -1,241 +0,0 @@
Overview
Implement comprehensive CRUD APIs for agent, agentSession, and agentSessionLogs management
in Cherry Studio's API server using RESTful URL conventions.
Architecture Overview
1. Service Layer
- Create AgentService class in src/main/services/agents/AgentService.ts
- Handles database operations using SQL queries from db.ts
- Manages SQLite database initialization and connections
- Provides business logic for agent operations
2. API Routes
- Create route files in src/main/apiServer/routes/:
- agents.ts - Agent CRUD endpoints
- sessions.ts - Session CRUD endpoints
- session-logs.ts - Session logs CRUD endpoints
3. Database Integration
- Use SQLite with @libsql/client (following MemoryService pattern)
- Database location: userData/agents.db
- Leverage existing SQL queries in src/main/services/agents/db.ts
Implementation Steps
Phase 1: Database Service Setup
1. Create AgentService class with database initialization
2. Implement database connection management
3. Add database initialization to main process startup
4. Create helper methods for JSON field serialization/deserialization
Phase 2: Agent CRUD Operations
1. Implement service methods:
- createAgent(agent: Omit<AgentEntity, 'id' | 'created_at' | 'updated_at'>)
- getAgent(id: string)
- listAgents(options?: { limit?: number, offset?: number })
- updateAgent(id: string, updates: Partial<AgentEntity>)
- deleteAgent(id: string)
2. Create API routes:
- POST /v1/agents - Create agent
- GET /v1/agents - List all agents
- GET /v1/agents/:agentId - Get agent by ID
- PUT /v1/agents/:agentId - Update agent
- DELETE /v1/agents/:agentId - Delete agent
Phase 3: Session CRUD Operations
1. Implement service methods:
- createSession(session: Omit<AgentSessionEntity, 'id' | 'created_at' | 'updated_at'>)
- getSession(id: string)
- listSessions(agentId?: string, options?: { status?: SessionStatus, limit?: number,
offset?: number })
- updateSession(id: string, updates: Partial<AgentSessionEntity>)
- updateSessionStatus(id: string, status: SessionStatus)
- deleteSession(id: string)
- getSessionWithAgent(id: string) - Get session with merged agent configuration
2. Create API routes (RESTful nested resources):
- POST /v1/agents/:agentId/sessions - Create session for specific agent
- GET /v1/agents/:agentId/sessions - List sessions for specific agent
- GET /v1/agents/:agentId/sessions/:sessionId - Get specific session
- PUT /v1/agents/:agentId/sessions/:sessionId - Update session
- PATCH /v1/agents/:agentId/sessions/:sessionId/status - Update session status
- DELETE /v1/agents/:agentId/sessions/:sessionId - Delete session
Additional convenience endpoints:
- GET /v1/sessions - List all sessions (across all agents)
- GET /v1/sessions/:sessionId - Get session by ID (without agent context)
Phase 4: Session Logs CRUD Operations
1. Implement service methods:
- createSessionLog(log: Omit<SessionLogEntity, 'id' | 'created_at' | 'updated_at'>)
- getSessionLog(id: number)
- listSessionLogs(sessionId: string, options?: { limit?: number, offset?: number })
- updateSessionLog(id: number, updates: { content?: any, metadata?: any })
- deleteSessionLog(id: number)
- getSessionLogTree(sessionId: string) - Get logs with parent-child relationships
- bulkCreateSessionLogs(logs: Array<...>) - Batch insert logs
2. Create API routes (RESTful nested resources):
- POST /v1/agents/:agentId/sessions/:sessionId/logs - Create log entry
- GET /v1/agents/:agentId/sessions/:sessionId/logs - List logs for session
- GET /v1/agents/:agentId/sessions/:sessionId/logs/:logId - Get specific log
- PUT /v1/agents/:agentId/sessions/:sessionId/logs/:logId - Update log
- DELETE /v1/agents/:agentId/sessions/:sessionId/logs/:logId - Delete log
- POST /v1/agents/:agentId/sessions/:sessionId/logs/bulk - Bulk create logs
Additional convenience endpoints:
- GET /v1/sessions/:sessionId/logs - Get logs without agent context
- GET /v1/session-logs/:logId - Get specific log by ID
Phase 5: Route Organization
1. Mount routes with proper nesting:
// In app.ts
apiRouter.use('/agents', agentsRoutes)
// agentsRoutes will handle:
// - /agents/_
// - /agents/:agentId/sessions/_
// - /agents/:agentId/sessions/:sessionId/logs/\*
// Convenience routes
apiRouter.use('/sessions', sessionsRoutes)
apiRouter.use('/session-logs', sessionLogsRoutes)
2. Use Express Router mergeParams for nested routes:
// In agents.ts
const sessionsRouter = express.Router({ mergeParams: true })
router.use('/:agentId/sessions', sessionsRouter)
Phase 6: OpenAPI Documentation
1. Add Swagger schemas for new entities:
- AgentEntity schema
- AgentSessionEntity schema
- SessionLogEntity schema
- Request/Response schemas
2. Document all new endpoints with:
- Clear path parameters (agentId, sessionId, logId)
- Request body schemas
- Response examples
- Error responses
- Proper grouping by resource
Phase 7: Validation & Error Handling
1. Add path parameter validation:
- Validate agentId exists before processing session requests
- Validate sessionId belongs to agentId
- Validate logId belongs to sessionId
2. Implement middleware for:
- Request validation using express-validator
- Resource existence checks
- Permission validation (future consideration)
- Transaction support for complex operations
Phase 8: Testing
1. Unit tests for service methods
2. Integration tests for API endpoints
3. Test nested resource validation
4. Test cascading deletes
5. Test transaction rollbacks
File Structure
src/
├── main/
│ └── services/
│ └── agents/
│ ├── index.ts (existing)
│ ├── db.ts (existing)
│ └── AgentService.ts (new)
├── main/
│ └── apiServer/
│ └── routes/
│ ├── agents.ts (new - includes nested routes)
│ ├── sessions.ts (new - convenience endpoints)
│ └── session-logs.ts (new - convenience endpoints)
└── renderer/
└── src/
└── types/
└── agent.ts (existing)
API Endpoint Summary
Agent Endpoints
- POST /v1/agents
- GET /v1/agents
- GET /v1/agents/:agentId
- PUT /v1/agents/:agentId
- DELETE /v1/agents/:agentId
Session Endpoints (RESTful)
- POST /v1/agents/:agentId/sessions
- GET /v1/agents/:agentId/sessions
- GET /v1/agents/:agentId/sessions/:sessionId
- PUT /v1/agents/:agentId/sessions/:sessionId
- PATCH /v1/agents/:agentId/sessions/:sessionId/status
- DELETE /v1/agents/:agentId/sessions/:sessionId
Session Convenience Endpoints
- GET /v1/sessions
- GET /v1/sessions/:sessionId
Session Log Endpoints (RESTful)
- POST /v1/agents/:agentId/sessions/:sessionId/logs
- GET /v1/agents/:agentId/sessions/:sessionId/logs
- GET /v1/agents/:agentId/sessions/:sessionId/logs/:logId
- PUT /v1/agents/:agentId/sessions/:sessionId/logs/:logId
- DELETE /v1/agents/:agentId/sessions/:sessionId/logs/:logId
- POST /v1/agents/:agentId/sessions/:sessionId/logs/bulk
Session Log Convenience Endpoints
- GET /v1/sessions/:sessionId/logs
- GET /v1/session-logs/:logId
Key Considerations
- Follow RESTful URL conventions with proper resource nesting
- Validate parent-child relationships in nested routes
- Use Express Router with mergeParams for nested routing
- Implement proper cascading deletes
- Add transaction support for data consistency
- Follow existing patterns from MemoryService
- Ensure backward compatibility
- Add rate limiting for write operations
Dependencies
- @libsql/client - SQLite database client
- express-validator - Request validation
- swagger-jsdoc - API documentation
- Existing types from @types/agent.ts