Add agent-facing wizard preview
This commit is contained in:
@@ -566,6 +566,16 @@ var TRANSLATIONS = {
|
||||
'wizard.step5.draft_actions': 'Action result',
|
||||
'wizard.step5.live_save_title': 'Saving before action',
|
||||
'wizard.step5.live_save_body': 'Crank saves the current settings before running checks or publishing.',
|
||||
'wizard.step5.agent_preview_title': 'How the MCP client sees this tool',
|
||||
'wizard.step5.agent_preview_subtitle': 'Check the name, description, input schema and examples before publication.',
|
||||
'wizard.step5.copy_agent_preview': 'Copy schema',
|
||||
'wizard.step5.preview_tool_name': 'Tool name',
|
||||
'wizard.step5.preview_tool_title': 'Short description',
|
||||
'wizard.step5.preview_tool_description': 'Description for the model',
|
||||
'wizard.step5.preview_input_schema': 'Input schema',
|
||||
'wizard.step5.preview_tool_call': 'Example tools/call',
|
||||
'wizard.step5.preview_success_response': 'Successful response example',
|
||||
'wizard.step5.preview_error_response': 'Error example',
|
||||
'wizard.step5.samples_title': 'Examples and automatic setup',
|
||||
'wizard.step5.samples_subtitle': 'Save example input and output data, then let Crank rebuild schemas and field bindings from them.',
|
||||
'wizard.step5.input_sample': 'Input example',
|
||||
@@ -652,6 +662,8 @@ var TRANSLATIONS = {
|
||||
'wizard.test.no_response_body': 'Run a test first, then copy the response into the output example.',
|
||||
'wizard.test.response_copied': 'Response copied',
|
||||
'wizard.test.response_copied_body': 'The latest test response was copied into the output example.',
|
||||
'wizard.agent_preview.copied': 'Schema copied',
|
||||
'wizard.agent_preview.copied_body': 'The MCP tool schema was copied to the clipboard.',
|
||||
'wizard.boolean.yes': 'yes',
|
||||
'wizard.boolean.no': 'no',
|
||||
'wizard.yaml.exported': 'YAML exported',
|
||||
@@ -1352,6 +1364,16 @@ var TRANSLATIONS = {
|
||||
'wizard.step5.draft_actions': 'Результат действия',
|
||||
'wizard.step5.live_save_title': 'Сохранение перед действием',
|
||||
'wizard.step5.live_save_body': 'Перед проверкой или публикацией Crank сохраняет текущие настройки.',
|
||||
'wizard.step5.agent_preview_title': 'Как инструмент увидит MCP клиент',
|
||||
'wizard.step5.agent_preview_subtitle': 'Проверьте имя, описание, входную схему и примеры до публикации.',
|
||||
'wizard.step5.copy_agent_preview': 'Копировать схему',
|
||||
'wizard.step5.preview_tool_name': 'Имя инструмента',
|
||||
'wizard.step5.preview_tool_title': 'Короткое описание',
|
||||
'wizard.step5.preview_tool_description': 'Описание для модели',
|
||||
'wizard.step5.preview_input_schema': 'Входная схема',
|
||||
'wizard.step5.preview_tool_call': 'Пример вызова tools/call',
|
||||
'wizard.step5.preview_success_response': 'Пример успешного ответа',
|
||||
'wizard.step5.preview_error_response': 'Пример ошибки',
|
||||
'wizard.step5.samples_title': 'Примеры и автоматическая настройка',
|
||||
'wizard.step5.samples_subtitle': 'Сохраните пример входных и выходных данных, затем Crank сможет пересобрать схемы и связи полей на их основе.',
|
||||
'wizard.step5.input_sample': 'Пример входных данных',
|
||||
@@ -1438,6 +1460,8 @@ var TRANSLATIONS = {
|
||||
'wizard.test.no_response_body': 'Сначала выполните тест, затем скопируйте ответ в выходной пример.',
|
||||
'wizard.test.response_copied': 'Ответ скопирован',
|
||||
'wizard.test.response_copied_body': 'Последний тестовый ответ скопирован в выходной пример.',
|
||||
'wizard.agent_preview.copied': 'Схема скопирована',
|
||||
'wizard.agent_preview.copied_body': 'Схема MCP инструмента скопирована в буфер обмена.',
|
||||
'wizard.boolean.yes': 'да',
|
||||
'wizard.boolean.no': 'нет',
|
||||
'wizard.yaml.exported': 'YAML экспортирован',
|
||||
|
||||
@@ -68,6 +68,7 @@ async function loadOperationForEdit() {
|
||||
wizardCurrentOperation = detail;
|
||||
wizardCurrentVersion = draftVersion;
|
||||
prefillWizardFromEdit(detail, draftVersion);
|
||||
renderAgentFacingPreview();
|
||||
}
|
||||
|
||||
function setEditModePresentation() {
|
||||
@@ -98,6 +99,7 @@ function bindWizardLiveActions() {
|
||||
bindLiveAction('wizard-generate-draft', tKey('wizard.busy.generate'), generateDraftFromWizard);
|
||||
bindLiveAction('wizard-run-test', tKey('wizard.busy.test'), runWizardTest);
|
||||
bindClick('wizard-copy-test-response', copyTestResponseToOutputSample);
|
||||
bindClick('wizard-copy-agent-preview', copyAgentFacingPreview);
|
||||
bindLiveAction('wizard-export-yaml', tKey('wizard.busy.export_yaml'), exportWizardYaml);
|
||||
bindLiveAction('wizard-import-yaml', tKey('wizard.busy.import_yaml'), importWizardYaml);
|
||||
bindLiveAction('wizard-publish-operation', tKey('wizard.busy.publish'), publishWizardOperation);
|
||||
@@ -108,6 +110,7 @@ function bindWizardLiveActions() {
|
||||
|
||||
var yamlInput = document.getElementById('wizard-import-yaml-file');
|
||||
if (yamlInput) yamlInput.addEventListener('change', handleImportYamlFileSelection);
|
||||
bindAgentFacingPreview();
|
||||
}
|
||||
|
||||
function bindClick(id, handler) {
|
||||
@@ -302,6 +305,99 @@ function setTextareaValue(id, value) {
|
||||
element.value = safeStringify(value);
|
||||
}
|
||||
|
||||
function setTextContent(id, value) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element) return;
|
||||
element.textContent = value || '';
|
||||
}
|
||||
|
||||
function structuredTextOrFallback(id, fallback) {
|
||||
try {
|
||||
var value = parseStructuredText(textValue(id));
|
||||
if (value === null || value === undefined || value === '') return fallback;
|
||||
return value;
|
||||
} catch (_error) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function buildAgentFacingPreview() {
|
||||
var inputSchema = structuredTextOrFallback('tool-input-schema', {});
|
||||
var inputSample = structuredTextOrFallback('wizard-input-sample', {});
|
||||
var outputSample = structuredTextOrFallback('wizard-output-sample', {});
|
||||
var toolName = textValue('tool-name') || 'unnamed_tool';
|
||||
var title = textValue('tool-title') || textValue('tool-display-name') || toolName;
|
||||
var description = textValue('tool-description');
|
||||
|
||||
return {
|
||||
manifest: {
|
||||
name: toolName,
|
||||
title: title,
|
||||
description: description,
|
||||
inputSchema: inputSchema,
|
||||
},
|
||||
toolCall: {
|
||||
name: toolName,
|
||||
arguments: inputSample,
|
||||
},
|
||||
successResponse: outputSample,
|
||||
errorResponse: {
|
||||
isError: true,
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Инструмент вернул ошибку. Проверьте входные параметры или состояние внешнего API.',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function renderAgentFacingPreview() {
|
||||
var root = document.getElementById('agent-facing-preview-card');
|
||||
if (!root) return;
|
||||
|
||||
var preview = buildAgentFacingPreview();
|
||||
setTextContent('agent-preview-tool-name', preview.manifest.name);
|
||||
setTextContent('agent-preview-tool-title', preview.manifest.title);
|
||||
setTextContent('agent-preview-tool-description', preview.manifest.description);
|
||||
setTextareaValue('agent-preview-input-schema', preview.manifest.inputSchema);
|
||||
setTextareaValue('agent-preview-tool-call', preview.toolCall);
|
||||
setTextareaValue('agent-preview-success-response', preview.successResponse);
|
||||
setTextareaValue('agent-preview-error-response', preview.errorResponse);
|
||||
}
|
||||
|
||||
function bindAgentFacingPreview() {
|
||||
[
|
||||
'tool-name',
|
||||
'tool-title',
|
||||
'tool-display-name',
|
||||
'tool-description',
|
||||
'tool-input-schema',
|
||||
'wizard-input-sample',
|
||||
'wizard-output-sample',
|
||||
].forEach(function(id) {
|
||||
var element = document.getElementById(id);
|
||||
if (!element || element.dataset.agentPreviewBound === 'true') return;
|
||||
element.dataset.agentPreviewBound = 'true';
|
||||
element.addEventListener('input', renderAgentFacingPreview);
|
||||
element.addEventListener('change', renderAgentFacingPreview);
|
||||
});
|
||||
renderAgentFacingPreview();
|
||||
}
|
||||
|
||||
function copyAgentFacingPreview() {
|
||||
var preview = buildAgentFacingPreview();
|
||||
var content = JSON.stringify(preview.manifest, null, 2);
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(content).then(function() {
|
||||
showWizardLiveStatus(tKey('wizard.agent_preview.copied'), tKey('wizard.agent_preview.copied_body'));
|
||||
}).catch(function() {
|
||||
setTextareaValue('agent-preview-input-schema', preview.manifest.inputSchema);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function exportWizardYaml() {
|
||||
await persistCurrentDraft(true);
|
||||
var yaml = await window.CrankApi.exportOperation(wizardWorkspaceId, wizardEditId, {
|
||||
@@ -386,6 +482,7 @@ async function generateDraftFromWizard() {
|
||||
setValue('tool-output-schema', JSON.stringify(crankSchemaToJsonSchema(generated.output_schema), null, 2));
|
||||
setValue('tool-input-mapping', mappingSetToEditorValue(generated.input_mapping, 'input', wizardProtocol));
|
||||
setValue('tool-output-mapping', mappingSetToEditorValue(generated.output_mapping, 'output', wizardProtocol));
|
||||
renderAgentFacingPreview();
|
||||
showWizardLiveStatus(tKey('wizard.sample.generated'), tKey('wizard.sample.generated_body'));
|
||||
}
|
||||
|
||||
@@ -413,6 +510,7 @@ function copyTestResponseToOutputSample() {
|
||||
return;
|
||||
}
|
||||
setTextareaValue('wizard-output-sample', wizardTestResponsePreview);
|
||||
renderAgentFacingPreview();
|
||||
showWizardLiveStatus(tKey('wizard.test.response_copied'), tKey('wizard.test.response_copied_body'));
|
||||
}
|
||||
|
||||
@@ -421,4 +519,5 @@ window.CrankWizardLive = {
|
||||
loadOperationForEdit: loadOperationForEdit,
|
||||
bindWizardLiveActions: bindWizardLiveActions,
|
||||
updateWizardProtocolVisibility: updateWizardProtocolVisibility,
|
||||
renderAgentFacingPreview: renderAgentFacingPreview,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user