TOOL-SPEC-open_composition_editor.md•14.1 kB
# open_composition_editor Tool Specification
**Version**: 1.0.0
**Created**: 2025-07-10
**Purpose**: Navigate to saved composition in EuConquisto Composer editor with enhanced debugging
---
## Overview
The `open_composition_editor` tool handles navigation to the saved composition in the Composer editor interface, ensuring successful page load and providing detailed debugging for navigation failures.
## Tool Interface
### Input Schema
```typescript
interface OpenCompositionEditorInput {
compositionUid: string;
page: PlaywrightPage; // Browser page with authentication context
}
```
### Output Schema
```typescript
interface OpenCompositionEditorOutput {
success: boolean;
data?: {
finalUrl: string;
pageTitle: string;
loadTime: number;
editorReady: boolean;
compositionLoaded: boolean;
};
error?: {
code: string;
message: string;
details: NavigationError;
};
debug?: {
timestamp: string;
processingTime: number;
navigationLog: NavigationLogEntry[];
pageAnalysis: PageAnalysis;
};
}
interface NavigationError {
step: string;
currentUrl: string;
targetUrl: string;
pageStatus: string;
consoleErrors: string[];
networkErrors: string[];
possibleCauses: string[];
suggestedFixes: string[];
}
interface PageAnalysis {
url: string;
title: string;
readyState: string;
hasComposerInterface: boolean;
errorIndicators: string[];
loadedAssets: number;
jsErrors: string[];
}
```
## Navigation Process
### 1. URL Construction
```typescript
function constructComposerUrl(baseUrl: string, compositionUid: string): NavigationPlan {
// Extract base URL from current page (removing any existing fragment)
const cleanBaseUrl = baseUrl.split('#')[0];
// Construct the composer editor path
const composerPath = `#/composer/${compositionUid}`;
const targetUrl = cleanBaseUrl + composerPath;
// Validate URL format
if (!isValidComposerUrl(targetUrl)) {
throw new Error(`Invalid composer URL format: ${targetUrl}`);
}
return {
baseUrl: cleanBaseUrl,
composerPath: composerPath,
targetUrl: targetUrl,
compositionUid: compositionUid
};
}
function isValidComposerUrl(url: string): boolean {
// Check URL contains required components
return url.includes('composer.euconquisto.com') &&
url.includes('#/composer/') &&
url.split('#/composer/')[1].length > 10; // Valid UID length
}
```
### 2. Pre-Navigation Checks
```typescript
async function performPreNavigationChecks(page: PlaywrightPage): Promise<PreNavigationStatus> {
const status = await page.evaluate(() => {
return {
currentUrl: window.location.href,
readyState: document.readyState,
hasAuthData: !!(localStorage.getItem('rdp-composer-user-data')),
hasProjectData: !!(localStorage.getItem('rdp-composer-active-project')),
networkState: navigator.onLine
};
});
const issues = [];
if (!status.hasAuthData) issues.push('Missing authentication data');
if (!status.hasProjectData) issues.push('Missing project data');
if (!status.networkState) issues.push('Network offline');
return {
ready: issues.length === 0,
issues: issues,
status: status
};
}
```
### 3. Navigation Execution
```typescript
async function executeNavigation(page: PlaywrightPage, navigationPlan: NavigationPlan): Promise<NavigationResult> {
const navigationLog: NavigationLogEntry[] = [];
try {
// Log navigation start
navigationLog.push({
timestamp: new Date().toISOString(),
step: 'NAVIGATION_START',
details: { targetUrl: navigationPlan.targetUrl },
success: true
});
// Set up page error monitoring
const pageErrors: string[] = [];
const networkErrors: string[] = [];
page.on('pageerror', (error) => {
pageErrors.push(error.message);
});
page.on('response', (response) => {
if (!response.ok()) {
networkErrors.push(`${response.status()} - ${response.url()}`);
}
});
// Execute navigation with timeout
const navigationStartTime = Date.now();
await page.goto(navigationPlan.targetUrl, {
waitUntil: 'networkidle',
timeout: 30000
});
const navigationTime = Date.now() - navigationStartTime;
navigationLog.push({
timestamp: new Date().toISOString(),
step: 'NAVIGATION_COMPLETE',
details: { loadTime: navigationTime, url: page.url() },
success: true
});
// Wait for Composer interface to load
await waitForComposerInterface(page, navigationLog);
// Verify composition loaded
const compositionStatus = await verifyCompositionLoaded(page, navigationPlan.compositionUid);
return {
success: true,
finalUrl: page.url(),
loadTime: navigationTime,
editorReady: compositionStatus.editorReady,
compositionLoaded: compositionStatus.compositionLoaded,
navigationLog: navigationLog,
pageErrors: pageErrors,
networkErrors: networkErrors
};
} catch (error) {
navigationLog.push({
timestamp: new Date().toISOString(),
step: 'NAVIGATION_FAILED',
details: { error: error.message },
success: false
});
throw new NavigationError({
step: 'NAVIGATION_EXECUTION',
message: error.message,
navigationLog: navigationLog
});
}
}
```
### 4. Composer Interface Detection
```typescript
async function waitForComposerInterface(page: PlaywrightPage, log: NavigationLogEntry[]): Promise<void> {
log.push({
timestamp: new Date().toISOString(),
step: 'WAITING_FOR_COMPOSER_INTERFACE',
details: {},
success: true
});
// Wait for key Composer elements to appear
await page.waitForFunction(() => {
// Check for Composer-specific elements
const composerApp = document.querySelector('[data-testid="composer-app"]') ||
document.querySelector('.composer-editor') ||
document.querySelector('#composer-root');
// Check for loading indicators to disappear
const loadingIndicators = document.querySelectorAll('.loading, .spinner, [data-loading="true"]');
return composerApp && loadingIndicators.length === 0;
}, {
timeout: 15000
});
// Additional wait for content stabilization
await page.waitForTimeout(2000);
log.push({
timestamp: new Date().toISOString(),
step: 'COMPOSER_INTERFACE_READY',
details: {},
success: true
});
}
```
### 5. Composition Load Verification
```typescript
async function verifyCompositionLoaded(page: PlaywrightPage, expectedUid: string): Promise<CompositionStatus> {
const status = await page.evaluate((uid) => {
// Check URL contains the composition UID
const urlContainsUid = window.location.href.includes(uid);
// Check for composition content in the DOM
const hasComposerContent = document.querySelector('.composer-widget') ||
document.querySelector('[data-widget-type]') ||
document.querySelector('.widget-container');
// Check for error indicators
const errorElements = document.querySelectorAll('.error, .not-found, [data-error="true"]');
const hasErrors = errorElements.length > 0;
// Check page title for composition info
const titleIndicatesComposition = document.title.includes('Composer') &&
!document.title.includes('Error');
return {
urlContainsUid: urlContainsUid,
hasComposerContent: !!hasComposerContent,
hasErrors: hasErrors,
titleIndicatesComposition: titleIndicatesComposition,
pageTitle: document.title,
errorMessages: Array.from(errorElements).map(el => el.textContent || '').filter(Boolean)
};
}, expectedUid);
const editorReady = status.titleIndicatesComposition && !status.hasErrors;
const compositionLoaded = status.urlContainsUid && status.hasComposerContent && !status.hasErrors;
return {
editorReady: editorReady,
compositionLoaded: compositionLoaded,
details: status
};
}
```
## Error Analysis & Debugging
### 1. Navigation Failure Analysis
```typescript
function analyzeNavigationFailure(error: any, page: PlaywrightPage): NavigationError {
const currentUrl = page.url();
let possibleCauses: string[] = [];
let suggestedFixes: string[] = [];
// Analyze by error type
if (error.message.includes('timeout')) {
possibleCauses = [
'Page load timeout (> 30 seconds)',
'Network connectivity issues',
'Composer server overloaded',
'Authentication session expired'
];
suggestedFixes = [
'Check network connection',
'Refresh authentication by reloading page',
'Try navigation again with longer timeout',
'Verify Composer service status'
];
} else if (currentUrl.includes('status/500')) {
possibleCauses = [
'Composition UID not found in database',
'Composition data corrupted',
'Server-side processing error',
'Database connectivity issues'
];
suggestedFixes = [
'Verify composition was saved successfully',
'Check composition UID format is valid',
'Try creating a new composition',
'Contact support with composition UID'
];
} else if (currentUrl.includes('login') || currentUrl.includes('auth')) {
possibleCauses = [
'Authentication session expired',
'Invalid or missing JWT token',
'User permissions revoked'
];
suggestedFixes = [
'Re-authenticate through JWT redirect server',
'Check JWT token file is current',
'Verify user has Composer access'
];
}
return {
step: 'NAVIGATION_ANALYSIS',
currentUrl: currentUrl,
targetUrl: error.targetUrl || 'Unknown',
pageStatus: error.pageStatus || 'Unknown',
consoleErrors: error.pageErrors || [],
networkErrors: error.networkErrors || [],
possibleCauses: possibleCauses,
suggestedFixes: suggestedFixes
};
}
```
### 2. Page Health Assessment
```typescript
async function assessPageHealth(page: PlaywrightPage): Promise<PageAnalysis> {
return await page.evaluate(() => {
// Check for various error indicators
const errorIndicators = [];
// HTTP error indicators
if (document.body.innerHTML.includes('500') || document.body.innerHTML.includes('Error')) {
errorIndicators.push('HTTP_ERROR_CONTENT');
}
// Authentication error indicators
if (document.body.innerHTML.includes('login') || document.body.innerHTML.includes('unauthorized')) {
errorIndicators.push('AUTH_ERROR_CONTENT');
}
// Composer-specific error indicators
if (document.body.innerHTML.includes('composition not found') ||
document.body.innerHTML.includes('access denied')) {
errorIndicators.push('COMPOSER_ERROR_CONTENT');
}
// Count loaded assets
const images = document.querySelectorAll('img[src]');
const scripts = document.querySelectorAll('script[src]');
const styles = document.querySelectorAll('link[rel="stylesheet"]');
const loadedAssets = images.length + scripts.length + styles.length;
// Check for Composer interface elements
const hasComposerInterface = !!(
document.querySelector('.composer-editor') ||
document.querySelector('[data-composer]') ||
document.querySelector('#composer-app')
);
return {
url: window.location.href,
title: document.title,
readyState: document.readyState,
hasComposerInterface: hasComposerInterface,
errorIndicators: errorIndicators,
loadedAssets: loadedAssets,
jsErrors: [] // Will be populated by page error listeners
};
});
}
```
## Error Codes
- **PRE_NAVIGATION_ERROR**: Failed pre-navigation checks
- **URL_CONSTRUCTION_ERROR**: Invalid URL construction
- **NAVIGATION_TIMEOUT**: Page load timeout exceeded
- **COMPOSER_INTERFACE_ERROR**: Composer interface failed to load
- **COMPOSITION_NOT_FOUND**: Composition UID not found or accessible
- **AUTHENTICATION_ERROR**: Authentication issues during navigation
- **NETWORK_ERROR**: Network connectivity problems
## Debug Output Standards
```typescript
interface NavigationLogEntry {
timestamp: string;
step: string;
details: any;
success: boolean;
}
// Example navigation log:
[
{
timestamp: '2025-07-10T10:30:05Z',
step: 'PRE_NAVIGATION_CHECK',
details: { hasAuth: true, hasProject: true, networkOnline: true },
success: true
},
{
timestamp: '2025-07-10T10:30:06Z',
step: 'URL_CONSTRUCTION',
details: { targetUrl: 'https://composer.euconquisto.com/#/composer/abc123' },
success: true
},
{
timestamp: '2025-07-10T10:30:07Z',
step: 'NAVIGATION_START',
details: { timeout: 30000 },
success: true
},
{
timestamp: '2025-07-10T10:30:12Z',
step: 'NAVIGATION_COMPLETE',
details: { loadTime: 5000, finalUrl: 'https://composer.euconquisto.com/#/composer/abc123' },
success: true
}
]
```
## Success Verification
### 1. Required Success Conditions
- Page navigation completes without timeout
- Final URL contains correct composition UID
- No 500/error status pages displayed
- Composer interface elements present
- Authentication persists through navigation
### 2. Optional Quality Indicators
- Page load time < 10 seconds
- No JavaScript console errors
- All assets loaded successfully
- Composition content visible in editor
## Integration Notes
- **Input**: Composition UID from `save_composition_api`
- **Output**: Final success/failure status for complete workflow
- **Browser Context**: Requires authenticated browser page
- **User Experience**: Browser remains open for user interaction
---
**Status**: Specification Complete
**Ready for Implementation**: Yes
**Dependencies**: Successful composition save, authenticated browser context
**Phase 1 Complete**: All 4 tool specifications defined with comprehensive error handling and debugging capabilities