Commit ede490db authored by jan.koester's avatar jan.koester
Browse files

llm agent mode

parent 4332f755
Loading
Loading
Loading
Loading
+6 −0
Changes for editor/html/css/editor.css: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -801,6 +801,12 @@ dialog.ai-panel::backdrop {
    align-self: flex-start;
    border-bottom-left-radius: 2px;
}
.ai-msg-status {
    color: var(--text-secondary);
    font-size: 11px;
    font-style: italic;
    margin-top: 4px;
}
.ai-msg.assistant .ai-msg-actions {
    display: flex; gap: 6px; margin-top: 6px;
}
+19 −2
Changes for editor/html/js/editor.js: 19 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -1649,7 +1649,12 @@
                currentAiRequest = null;
                statusEl.remove();
                var result = resp.result || '';
                addAssistantMessage(result);
                if (resp.applied) {
                    Canvas.clearSelection(); DocumentTree.clearSelection();
                    PropertiesPanel.clear();
                    refreshDocument();
                }
                addAssistantMessage(result, false, !!resp.applied, resp.tool_calls || 0);
                resetSendBtn();
            }).catch(function(err) {
                currentAiRequest = null;
@@ -1680,7 +1685,7 @@
            return div;
        }

        function addAssistantMessage(text, noSave) {
        function addAssistantMessage(text, noSave, applied, toolCalls) {
            var div = document.createElement('div');
            div.className = 'ai-msg assistant';

@@ -1688,6 +1693,14 @@
            content.textContent = text;
            div.appendChild(content);

            if (applied) {
                var appliedStatus = document.createElement('div');
                appliedStatus.className = 'ai-msg-status';
                appliedStatus.textContent = '\u2713 ' + (toolCalls || 0) + ' ' +
                    I18n.t('I18N_AI_APPLIED', '\u00C4nderung(en) direkt am Dokument angewendet');
                div.appendChild(appliedStatus);
            }

            var actions = document.createElement('div');
            actions.className = 'ai-msg-actions';

@@ -1701,6 +1714,9 @@
            });
            actions.appendChild(copyBtn);

            // The model already applied its changes directly via tool calls --
            // no manual Replace/Child import buttons needed in that case.
            if (!applied) {
                function doImport(mode) {
                    var htmlContent = extractHtml(text);
                    var parentUuid = (mode === 'child') ? Canvas.getSelectedUuid() : null;
@@ -1730,6 +1746,7 @@
                childBtn.textContent = '\u2B07 ' + I18n.t('I18N_INSERT_CHILD', 'Child einf\u00fcgen');
                childBtn.addEventListener('click', function() { doImport('child'); });
                actions.appendChild(childBtn);
            }

            div.appendChild(actions);
            chatHistory.appendChild(div);
+417 −91

File changed.

Preview size limit exceeded, changes collapsed.

+9 −0
Changes for editor/src/webedit_api.h: 9 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -287,6 +287,15 @@ namespace webedit {
        void mcpLoadDocument(const std::string &domain, const std::string &docId, DocumentState &doc);
        void mcpSaveDocument(const std::string &domain, const std::string &docId, DocumentState &doc);

        // Session-scoped counterpart of the mcpXxx tool entry points, used by the
        // in-editor AI chat (handleAiPrompt): dispatches on the same tool names/
        // semantics as Mcp::callTool, but acts directly on getDocState(sessionid)
        // instead of a (domain, docId)-loaded DB copy, so calls mutate the live
        // document the browser has open. Throws McpError on failure; sets
        // mutated=true if the tool changed the document.
        json_object *callAiTool(const std::string &sessionid, const std::string &name,
                                json_object *args, bool &mutated);

        // Core element-mutation logic shared by the handleXxx HTTP handlers and the
        // mcpXxx entry points (kept in one place because the sibling/child pointer
        // splicing here has real correctness subtlety). Throw McpError on failure.
+10 −16
Changes for editor/src/webedit_mcp.cpp: 10 added lines, 16 removed lines.
Original line number Diff line number Diff line
@@ -90,13 +90,17 @@ json_object *getObjectArg(json_object *args, const char *key) {
    return v;
}

struct SchemaProp {
    const char *name;
    const char *type;
    const char *description;
};
json_object *makeTool(const char *name, const char *description, json_object *schema) {
    json_object *tool = json_object_new_object();
    json_object_object_add(tool, "name", json_object_new_string(name));
    json_object_object_add(tool, "description", json_object_new_string(description));
    json_object_object_add(tool, "inputSchema", schema);
    return tool;
}

json_object *makeSchema(std::initializer_list<SchemaProp> props,
} // namespace

json_object *webedit::makeSchema(std::initializer_list<SchemaProp> props,
                                  std::initializer_list<const char*> required) {
    json_object *propsObj = json_object_new_object();
    for (const auto &p : props) {
@@ -120,16 +124,6 @@ json_object *makeSchema(std::initializer_list<SchemaProp> props,
    return schema;
}

json_object *makeTool(const char *name, const char *description, json_object *schema) {
    json_object *tool = json_object_new_object();
    json_object_object_add(tool, "name", json_object_new_string(name));
    json_object_object_add(tool, "description", json_object_new_string(description));
    json_object_object_add(tool, "inputSchema", schema);
    return tool;
}

} // namespace

webedit::Mcp::Mcp(Database &db, Api &api) : _db(db), _api(api) {
}

Loading