From 44dfb9d8d54cc3c08148ecc654d04bf4fce362f3 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Mon, 5 Oct 2026 18:32:42 +1300 Subject: [PATCH] Assistant house style: a drawing-convention text every AI assistant reads QetSettings::houseStyle()/setHouseStyle() (assistant/house_style), qet.houseStyle()/qet.setHouseStyle() in the script API, a house_style field in qet-assistant.json, and qet_about in the qet MCP server showing it. Co-Authored-By: Claude Opus 5.5 --- misc/qet-mcp/qet_mcp.py | 18 +++++++++++++++--- misc/qet-mcp/test_qet_mcp.py | 9 +++++++++ sources/scripting/assistantinfo.cpp | 9 ++++++++- sources/scripting/qetscriptapi.cpp | 27 +++++++++++++++++++++++++++ sources/scripting/qetscriptapi.h | 5 +++++ sources/utils/qetsettings.cpp | 17 +++++++++++++++++ sources/utils/qetsettings.h | 10 ++++++++++ 7 files changed, 91 insertions(+), 4 deletions(-) diff --git a/misc/qet-mcp/qet_mcp.py b/misc/qet-mcp/qet_mcp.py index df5c2a157..d96e7b018 100755 --- a/misc/qet-mcp/qet_mcp.py +++ b/misc/qet-mcp/qet_mcp.py @@ -3650,7 +3650,9 @@ SERVER_INSTRUCTIONS = ( "diagrams. A project (.qet) holds folios (sheets) of symbols " "(elements) joined by wires (conductors). Folio indexes count from 0.\n" "Start with qet_about: where QElectroTech keeps things, what is " - "switched on, and the stored scripts.\n" + "switched on, the stored scripts, and house_style -- this " + "installation's own drawing conventions if the user set any. Follow " + "house_style when placing or wiring anything.\n" "Two ways of working. HEADLESS (qet_* and qet_script_*): read, check " "and edit .qet files and store script buttons; nothing the user has " "open is touched. To make a button: qet_script_api for the calls, " @@ -3701,6 +3703,12 @@ def tool_about() -> dict: "script_api": info.get("script_api"), # Never the token: it is for the live tools, not the conversation. "live": {"open": bool(live), "pid": (live or {}).get("pid")}, + # This installation's drawing conventions, set once via + # qet.setHouseStyle() (scripting consent required, same as any + # other write) and read here so every assistant that connects sees + # them without being told by the user each time. No GUI field yet + # -- QetSettings::setHouseStyle() is there for one if it is wanted. + "house_style": info.get("house_style"), }) return out @@ -5186,8 +5194,12 @@ TOOLS = [ "scripts, element and title block collections), which " "features are on (scripting, live mode), every call a script " "can make, the stored scripts and the ones refused with why, " - "and whether a live session is open; plus this server's own " - "setup. Reads one file; changes nothing.", + "whether a live session is open, and house_style -- this " + "installation's own drawing conventions, in the user's words, " + "if they set any (qet.setHouseStyle()); null if not. Read " + "house_style and follow it, the same as any explicit " + "instruction, before placing or wiring anything. " + "Reads one file; changes nothing.", "inputSchema": {"type": "object", "properties": {}}, "handler": lambda a: tool_about(), }, diff --git a/misc/qet-mcp/test_qet_mcp.py b/misc/qet-mcp/test_qet_mcp.py index b4524d7ed..25f979c29 100644 --- a/misc/qet-mcp/test_qet_mcp.py +++ b/misc/qet-mcp/test_qet_mcp.py @@ -3584,6 +3584,15 @@ class AssistantInfoFile(unittest.TestCase): self.assertNotIn("SECRET", json.dumps(about)) self.assertEqual(about["script_api"], ["int currentFolio()"]) + def test_house_style_passes_through(self): + self.write(house_style="Grid: never off. Inputs left, outputs right.") + about = m.tool_about() + self.assertEqual(about["house_style"], "Grid: never off. Inputs left, outputs right.") + + def test_house_style_null_when_unset(self): + self.write(house_style=None) + self.assertIsNone(m.tool_about()["house_style"]) + def test_first_contact_carries_the_instructions(self): reply = m.handle({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}) self.assertIn("qet_about", reply["result"]["instructions"]) diff --git a/sources/scripting/assistantinfo.cpp b/sources/scripting/assistantinfo.cpp index 88193b5a0..a6a81eab8 100644 --- a/sources/scripting/assistantinfo.cpp +++ b/sources/scripting/assistantinfo.cpp @@ -111,7 +111,14 @@ void write() {QStringLiteral("stored_scripts"), scripts}, {QStringLiteral("refused_scripts"), refused}, {QStringLiteral("recordings"), MacroRecorder::recordings()}, - {QStringLiteral("live"), s_live.isEmpty() ? QJsonValue() : QJsonValue(s_live)}}; + {QStringLiteral("live"), s_live.isEmpty() ? QJsonValue() : QJsonValue(s_live)}, + // Free-text drawing conventions, set once by the user + // (QetSettings::setHouseStyle(), qet.setHouseStyle()) and read + // by any assistant that connects, live or headless, without it + // having to ask the user or guess. Null, not "", when unset -- + // the two mean different things to a reader. + {QStringLiteral("house_style"), QetSettings::houseStyle().isEmpty() + ? QJsonValue() : QJsonValue(QetSettings::houseStyle())}}; const QString file_path = path(); QDir().mkpath(QFileInfo(file_path).path()); diff --git a/sources/scripting/qetscriptapi.cpp b/sources/scripting/qetscriptapi.cpp index 0de2b7497..e8bdddf9d 100644 --- a/sources/scripting/qetscriptapi.cpp +++ b/sources/scripting/qetscriptapi.cpp @@ -44,6 +44,7 @@ #include "../conductorsegment.h" #include "../conductorrouter.h" #include "../qetgraphicsitem/diagramimageitem.h" +#include "../utils/qetsettings.h" // See diagrameventaddpdf.h: a missing QtPdf module (or Qt < 6.4) is not // fatal at build time, so addPdfPage() is always declared -- a script @@ -4200,6 +4201,32 @@ QStringList QetScriptApi::folioPresets() const return names; } +/** + @brief QetScriptApi::houseStyle + This installation's drawing conventions (grid, flow direction, routing, + tagging, grouping, ...), as free text the user wrote once. Empty when + nobody has set any. Not project-scoped: the same text for every + project this QElectroTech opens, same as liveAssistantEnabled(). + @return the text +*/ +QString QetScriptApi::houseStyle() const +{ + return QetSettings::houseStyle(); +} + +/** + @brief QetScriptApi::setHouseStyle + Write the installation's drawing conventions. Always succeeds (a plain + setting, not project data, so there is nothing here to refuse); @return + is for a consistent call shape with the rest of the API. + @param text +*/ +bool QetScriptApi::setHouseStyle(const QString &text) +{ + QetSettings::setHouseStyle(text); + return true; +} + /** @brief QetScriptApi::setFolioBorder Change one field of a folio's frame through ChangeBorderCommand, as the diff --git a/sources/scripting/qetscriptapi.h b/sources/scripting/qetscriptapi.h index 572168a0f..202b8f936 100644 --- a/sources/scripting/qetscriptapi.h +++ b/sources/scripting/qetscriptapi.h @@ -567,6 +567,11 @@ class QetScriptApi : public QObject Q_INVOKABLE bool setFolioBorder(int folioIndex, const QString &property, const QString &value); Q_INVOKABLE QStringList folioPresets() const; + // -- this installation's drawing conventions (grid, flow, routing, tagging, -- + // -- grouping, ...), free text, for every assistant that connects to read -- + Q_INVOKABLE QString houseStyle() const; + Q_INVOKABLE bool setHouseStyle(const QString &text); + // -- the conductor defaults of a folio (Folio properties > Conductors), // or with folioIndex -1, the project's defaults for new folios -- Q_INVOKABLE QString conductorDefault(int folioIndex, const QString &property) const; diff --git a/sources/utils/qetsettings.cpp b/sources/utils/qetsettings.cpp index 43adb2ce4..de5f6e6b4 100644 --- a/sources/utils/qetsettings.cpp +++ b/sources/utils/qetsettings.cpp @@ -173,6 +173,23 @@ namespace QetSettings settings.setValue("scripting/live_assistant", enabled); } + /** + * @brief houseStyle + * @return this installation's drawing conventions, in the user's own + * words -- empty when nobody has set any. + */ + QString houseStyle() + { + QSettings settings; + return settings.value("assistant/house_style", QString()).toString(); + } + + void setHouseStyle(const QString &text) + { + QSettings settings; + settings.setValue("assistant/house_style", text); + } + /** * @brief setSheetBackground * Store the sheet background last picked in the diagram editor, so the diff --git a/sources/utils/qetsettings.h b/sources/utils/qetsettings.h index 64bf4b615..abea8d460 100644 --- a/sources/utils/qetsettings.h +++ b/sources/utils/qetsettings.h @@ -41,6 +41,16 @@ namespace QetSettings bool liveAssistantEnabled(); void setLiveAssistantEnabled(bool enabled); + /** + @brief Free-text drawing conventions for this installation (grid, + flow direction, routing, tagging, grouping, ...), written once by + the user and read by every AI assistant that connects -- live or + headless -- through qet-assistant.json and qet.houseStyle(). + Empty when never set. + */ + QString houseStyle(); + void setHouseStyle(const QString &text); + /** @brief The sheet (folio) background the diagram editors draw.