diff --git a/src/Kompas.Mcp.Core/Modeling/VariableService.cs b/src/Kompas.Mcp.Core/Modeling/VariableService.cs index f810177..02aa2a4 100644 --- a/src/Kompas.Mcp.Core/Modeling/VariableService.cs +++ b/src/Kompas.Mcp.Core/Modeling/VariableService.cs @@ -38,7 +38,8 @@ public sealed class VariableService var v = vc.AddNewVariable(name, value, note ?? "") as ksVariable ?? throw new InvalidOperationException("AddNewVariable вернул null (недопустимое имя?)."); if (external) v.external = true; - part.RebuildModel(); + if (!part.RebuildModel()) + throw new InvalidOperationException($"Не удалось применить создание переменной '{name}' (RebuildModel вернул FALSE)."); return ReadValueFresh(name); // значение перечитываем после перестроения }, ct); @@ -53,7 +54,9 @@ public sealed class VariableService var (part, vc) = RootVariables(); var v = RequireVariable(vc, name); v.Expression = expression; - part.RebuildModel(); + if (!part.RebuildModel()) + throw new InvalidOperationException( + $"Не удалось пересчитать модель с выражением «{expression}» для '{name}' (недопустимое выражение или ссылка на несуществующую переменную?)."); return ReadValueFresh(name); // переменную перечитываем после перестроения (value пересчитан) }, ct); @@ -65,8 +68,10 @@ public sealed class VariableService var (part, vc) = RootVariables(); RequireVariable(vc, name); // понятная ошибка, если её нет if (!vc.RemoveVariable(name)) - throw new InvalidOperationException($"Не удалось удалить переменную '{name}'."); - part.RebuildModel(); + throw new InvalidOperationException( + $"Не удалось удалить переменную '{name}' (возможно, на неё ссылаются другие переменные — удалите зависимые сначала)."); + if (!part.RebuildModel()) + throw new InvalidOperationException($"Не удалось применить удаление переменной '{name}' (RebuildModel вернул FALSE)."); }, ct); /// Прочитать текущее (вычисленное) значение переменной. diff --git a/src/Kompas.Mcp.Host/Tools/VariableTools.cs b/src/Kompas.Mcp.Host/Tools/VariableTools.cs index 7f89f2e..56b433e 100644 --- a/src/Kompas.Mcp.Host/Tools/VariableTools.cs +++ b/src/Kompas.Mcp.Host/Tools/VariableTools.cs @@ -23,7 +23,7 @@ public sealed class VariableTools(KompasSession session, VariableService variabl } [McpServerTool(Name = "set_variable")] - [Description("Задать выражение существующей переменной: константа (например «30») или формула со ссылками на другие переменные (например «width*2+5»). Модель перестраивается, значение пересчитывается. Возвращает вычисленное значение.")] + [Description("Задать выражение существующей переменной: константа (например «30») или формула со ссылками на другие переменные (например «width*2+5»). Модель перестраивается, значение пересчитывается. Десятичный разделитель — точка. Примечание: изменит геометрию только в параметрической модели (где размеры эскизов связаны с именами переменных); для моделей с литеральными размерами значение пересчитается, но геометрия не изменится. Возвращает вычисленное значение.")] public async Task SetVariable( string name, [Description("Выражение: число или формула (width*2+5)")] string expression) diff --git a/tests/Kompas.Mcp.Tests/Integration/VariableTests.cs b/tests/Kompas.Mcp.Tests/Integration/VariableTests.cs index bff3b3f..3e192dc 100644 --- a/tests/Kompas.Mcp.Tests/Integration/VariableTests.cs +++ b/tests/Kompas.Mcp.Tests/Integration/VariableTests.cs @@ -48,11 +48,21 @@ public sealed class VariableTests Assert.Equal(20, computed, 3); Assert.Equal(20, await _vars.GetVariableValueAsync("width"), 3); + // дубликат имени отвергается + await Assert.ThrowsAsync(() => _vars.CreateVariableAsync("width", 1)); + // вторая переменная, ссылающаяся на первую (формула с именем переменной) await _vars.CreateVariableAsync("height", 5); var doubled = await _vars.SetVariableAsync("height", "width * 2"); Assert.Equal(40, doubled, 3); // width=20 → 40 + // десятичный разделитель — точка; зависимая переменная пересчитывается + Assert.Equal(3.5, await _vars.SetVariableAsync("width", "3.5"), 3); + Assert.Equal(7, await _vars.GetVariableValueAsync("height"), 3); // 3.5*2 + + // нельзя удалить переменную, на которую ссылаются (height = width*2) + await Assert.ThrowsAsync(() => _vars.DeleteVariableAsync("width")); + // delete (в порядке зависимостей: сначала зависимая height, затем width) await _vars.DeleteVariableAsync("height"); await _vars.DeleteVariableAsync("width");