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");