Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x | import {
Controller,
Post,
Body,
HttpCode,
HttpStatus,
Logger,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { SessionsService } from '../sessions/sessions.service';
import { SessionInputsService } from '../session-inputs/session-inputs.service';
import { ApplicationStateService } from '../application-state/application-state.service';
import { SubmitVisualPromptDto } from './visual-editor.dto';
/**
* Visual Editor endpoints handle prompts from the visual selection mode.
*
* The visual editor proxy allows selecting UI elements in a running application
* and sending their component context as part of a prompt. This enables
* "point and click" AI modifications to React components.
*
* Workflow:
* 1. User clicks visual selector button in the target app
* 2. Selects a UI element to modify
* 3. Component path and context are sent to this endpoint
* 4. Backend creates a session input with the component files as context
* 5. LLM generates modifications for the selected component
*/
@ApiTags('visual-editor')
@Controller('visual-editor')
export class VisualEditorController {
private readonly logger = new Logger(VisualEditorController.name);
constructor(
private readonly sessionsService: SessionsService,
private readonly sessionInputsService: SessionInputsService,
private readonly applicationStateService: ApplicationStateService,
) {}
@Post('submit')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: 'Submit visual editor prompt',
description:
'Submit a prompt from the visual editor with selected component context. Creates a session input with the component files included as context.',
})
@ApiResponse({
status: 200,
description: 'Prompt submitted successfully',
schema: {
properties: {
message: { type: 'string', example: 'Prompt submitted successfully' },
},
},
})
async submitVisualPrompt(@Body() submitDto: SubmitVisualPromptDto) {
this.logger.log('Received prompt from visual editor');
let sessionId = await this.applicationStateService.getActiveSessionId();
if (!sessionId) {
this.logger.log('No active session found. Creating a new one.');
const newSession = await this.sessionsService.create({
session_title: 'New Visual Editor Session',
});
sessionId = newSession.id;
this.logger.log(`Created new session with ID: ${sessionId}`);
} else {
this.logger.log(`Using active session ID: ${sessionId}`);
}
const adHocFiles = [];
Iif (submitDto.componentPath) {
adHocFiles.push(submitDto.componentPath);
}
Iif (submitDto.parentComponentPath) {
adHocFiles.push(submitDto.parentComponentPath);
}
const ad_hoc_context_definition = JSON.stringify({
files: adHocFiles,
folders: [],
command_outputs: [],
});
// We fetch the session details to correctly determine the context template.
const sessionDetails = await this.sessionsService.findOne(sessionId);
const existingInputsCount = sessionDetails.sessionInputs?.length || 0;
const isFirstPrompt = existingInputsCount === 0;
const templateId = isFirstPrompt
? sessionDetails.default_initial_context_template_id
: sessionDetails.default_followup_context_template_id;
await this.sessionInputsService.create(sessionId, {
user_prompt: submitDto.prompt,
execution_strategy: 'apply_revert',
context_template_id: templateId || null,
ad_hoc_context_definition: ad_hoc_context_definition,
});
this.logger.log(
`Successfully created new session input in session ${sessionId}`,
);
return { message: 'Prompt submitted successfully' };
}
}
|