solidworks-mcp-python 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. solidworks_mcp/__init__.py +57 -0
  2. solidworks_mcp/adapters/__init__.py +40 -0
  3. solidworks_mcp/adapters/base.py +1882 -0
  4. solidworks_mcp/adapters/circuit_breaker.py +2052 -0
  5. solidworks_mcp/adapters/com_executor.py +252 -0
  6. solidworks_mcp/adapters/complexity_analyzer.py +272 -0
  7. solidworks_mcp/adapters/connection_pool.py +1884 -0
  8. solidworks_mcp/adapters/factory.py +366 -0
  9. solidworks_mcp/adapters/intelligent_router.py +218 -0
  10. solidworks_mcp/adapters/mock_adapter.py +4016 -0
  11. solidworks_mcp/adapters/pywin32_adapter.py +2842 -0
  12. solidworks_mcp/adapters/solidworks/__init__.py +17 -0
  13. solidworks_mcp/adapters/solidworks/bitmap.py +180 -0
  14. solidworks_mcp/adapters/solidworks/com_utils.py +56 -0
  15. solidworks_mcp/adapters/solidworks/dimension_layout.py +753 -0
  16. solidworks_mcp/adapters/solidworks/documentation.py +1476 -0
  17. solidworks_mcp/adapters/solidworks/drawing_standard.py +1993 -0
  18. solidworks_mcp/adapters/solidworks/face_selection.py +392 -0
  19. solidworks_mcp/adapters/solidworks/features.py +3362 -0
  20. solidworks_mcp/adapters/solidworks/io.py +3649 -0
  21. solidworks_mcp/adapters/solidworks/rebuild_diagnostics.py +269 -0
  22. solidworks_mcp/adapters/solidworks/rebuild_inspector.py +146 -0
  23. solidworks_mcp/adapters/solidworks/selection.py +308 -0
  24. solidworks_mcp/adapters/solidworks/sketch.py +2545 -0
  25. solidworks_mcp/adapters/sw_feature_errors.py +66 -0
  26. solidworks_mcp/adapters/sw_type_info.py +317 -0
  27. solidworks_mcp/adapters/vba_adapter.py +318 -0
  28. solidworks_mcp/adapters/vba_macro_executor.py +215 -0
  29. solidworks_mcp/agents/__init__.py +68 -0
  30. solidworks_mcp/agents/design_knowledge/assembly_patterns.md +127 -0
  31. solidworks_mcp/agents/design_knowledge/hinges.md +118 -0
  32. solidworks_mcp/agents/design_knowledge/snap_fits.md +93 -0
  33. solidworks_mcp/agents/design_knowledge/solidworks_basics.md +3 -0
  34. solidworks_mcp/agents/design_knowledge/tolerancing.md +128 -0
  35. solidworks_mcp/agents/harness.py +216 -0
  36. solidworks_mcp/agents/history_db.py +1508 -0
  37. solidworks_mcp/agents/retrieval_index.py +164 -0
  38. solidworks_mcp/agents/schemas.py +165 -0
  39. solidworks_mcp/agents/smoke_test.py +285 -0
  40. solidworks_mcp/agents/soc_exporter.py +650 -0
  41. solidworks_mcp/agents/soc_pickup.py +332 -0
  42. solidworks_mcp/agents/soc_rewind.py +221 -0
  43. solidworks_mcp/agents/vector_rag.py +665 -0
  44. solidworks_mcp/cache/__init__.py +5 -0
  45. solidworks_mcp/cache/response_cache.py +164 -0
  46. solidworks_mcp/config.py +729 -0
  47. solidworks_mcp/exceptions.py +37 -0
  48. solidworks_mcp/security/__init__.py +68 -0
  49. solidworks_mcp/security/auth.py +128 -0
  50. solidworks_mcp/security/cors.py +27 -0
  51. solidworks_mcp/security/rate_limiting.py +90 -0
  52. solidworks_mcp/security/runtime.py +155 -0
  53. solidworks_mcp/server.py +777 -0
  54. solidworks_mcp/server_cli_fixed.py +120 -0
  55. solidworks_mcp/setup/__init__.py +1 -0
  56. solidworks_mcp/setup/cli.py +399 -0
  57. solidworks_mcp/setup/clients.py +157 -0
  58. solidworks_mcp/setup/config_file.py +230 -0
  59. solidworks_mcp/setup/handshake.py +202 -0
  60. solidworks_mcp/setup/launcher.py +102 -0
  61. solidworks_mcp/setup/legacy.py +100 -0
  62. solidworks_mcp/setup/registration.py +193 -0
  63. solidworks_mcp/setup/solidworks.py +49 -0
  64. solidworks_mcp/tools/__init__.py +64 -0
  65. solidworks_mcp/tools/analysis.py +723 -0
  66. solidworks_mcp/tools/automation.py +578 -0
  67. solidworks_mcp/tools/docs_discovery.py +1476 -0
  68. solidworks_mcp/tools/drawing.py +1015 -0
  69. solidworks_mcp/tools/drawing_analysis.py +456 -0
  70. solidworks_mcp/tools/drawing_automation.py +627 -0
  71. solidworks_mcp/tools/engineering_data.py +466 -0
  72. solidworks_mcp/tools/error_classifier.py +232 -0
  73. solidworks_mcp/tools/export.py +833 -0
  74. solidworks_mcp/tools/file_facts.py +40 -0
  75. solidworks_mcp/tools/file_management.py +1473 -0
  76. solidworks_mcp/tools/input_compat.py +17 -0
  77. solidworks_mcp/tools/macro_recording.py +464 -0
  78. solidworks_mcp/tools/modeling.py +2360 -0
  79. solidworks_mcp/tools/sketching.py +1422 -0
  80. solidworks_mcp/tools/template_management.py +367 -0
  81. solidworks_mcp/tools/tool_boundary.py +280 -0
  82. solidworks_mcp/tools/vba_generation.py +1145 -0
  83. solidworks_mcp/ui/__init__.py +9 -0
  84. solidworks_mcp/ui/local_llm.py +725 -0
  85. solidworks_mcp/ui/routers/__init__.py +10 -0
  86. solidworks_mcp/ui/routers/checkpoint.py +24 -0
  87. solidworks_mcp/ui/routers/docs.py +47 -0
  88. solidworks_mcp/ui/routers/llm.py +83 -0
  89. solidworks_mcp/ui/routers/local_model.py +69 -0
  90. solidworks_mcp/ui/routers/model.py +75 -0
  91. solidworks_mcp/ui/routers/preview.py +38 -0
  92. solidworks_mcp/ui/routers/session.py +161 -0
  93. solidworks_mcp/ui/routers/viewer.py +154 -0
  94. solidworks_mcp/ui/schemas.py +502 -0
  95. solidworks_mcp/ui/server.py +298 -0
  96. solidworks_mcp/ui/service.py +481 -0
  97. solidworks_mcp/ui/services/__init__.py +136 -0
  98. solidworks_mcp/ui/services/_utils.py +958 -0
  99. solidworks_mcp/ui/services/checkpoint_service.py +1110 -0
  100. solidworks_mcp/ui/services/docs_service.py +282 -0
  101. solidworks_mcp/ui/services/llm_service.py +956 -0
  102. solidworks_mcp/ui/services/model_service.py +459 -0
  103. solidworks_mcp/ui/services/parameter_repair_service.py +314 -0
  104. solidworks_mcp/ui/services/preview_service.py +489 -0
  105. solidworks_mcp/ui/services/session_service.py +1389 -0
  106. solidworks_mcp/utils/__init__.py +9 -0
  107. solidworks_mcp/utils/feature_tree_classifier.py +342 -0
  108. solidworks_mcp/utils/logging.py +76 -0
  109. solidworks_mcp/utils/validation.py +77 -0
  110. solidworks_mcp/version.py +8 -0
  111. solidworks_mcp_python-1.5.0.dist-info/METADATA +410 -0
  112. solidworks_mcp_python-1.5.0.dist-info/RECORD +115 -0
  113. solidworks_mcp_python-1.5.0.dist-info/WHEEL +4 -0
  114. solidworks_mcp_python-1.5.0.dist-info/entry_points.txt +3 -0
  115. solidworks_mcp_python-1.5.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,252 @@
1
+ """
2
+ Single-threaded executor for SolidWorks COM calls.
3
+
4
+ Background: SolidWorks COM is STA (single-threaded apartment). An
5
+ ``IDispatch`` proxy obtained on thread A cannot be invoked from thread B —
6
+ pywin32's late-binding surfaces this as
7
+ ``AttributeError: SldWorks.Application.<method>``. FastMCP dispatches async
8
+ tool handlers on worker threads that are *not* the thread where
9
+ ``connect()`` ran, so any cached ``swApp`` reference breaks.
10
+
11
+ This module provides a single dedicated STA worker thread (``ComExecutor``).
12
+ All COM work is submitted to it as callables and awaited via ``Future``.
13
+ Because exactly one thread ever touches COM:
14
+
15
+ 1. ``CoInitialize()`` is called once at thread startup.
16
+ 2. ``self.swApp`` and ``self.currentModel`` can be shared instance attributes
17
+ without marshalling — no thread-local trickery.
18
+ 3. STA constraints are satisfied (SW is happy).
19
+ 4. ``_FlagAsMethod`` results accumulate on the same object lifetime.
20
+
21
+ Usage:
22
+
23
+ executor = ComExecutor()
24
+ executor.start()
25
+ try:
26
+ result = executor.submit(lambda: sw.ActiveDoc.GetTitle())
27
+ finally:
28
+ executor.stop()
29
+
30
+ or with the synchronous helper:
31
+
32
+ with ComExecutor() as ex:
33
+ title = ex.run(lambda: sw.ActiveDoc.GetTitle())
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ import queue
39
+ import threading
40
+ from collections.abc import Callable
41
+ from concurrent.futures import Future
42
+ from typing import Any, TypeVar
43
+
44
+ from loguru import logger
45
+
46
+ try:
47
+ import pythoncom
48
+
49
+ PYWIN32_AVAILABLE = True
50
+ except ImportError:
51
+ PYWIN32_AVAILABLE = False
52
+
53
+
54
+ T = TypeVar("T")
55
+
56
+
57
+ # Sentinel object used to signal the worker thread to exit.
58
+ _SHUTDOWN = object()
59
+
60
+
61
+ class ComExecutor:
62
+ """Single-threaded STA executor for SolidWorks COM calls.
63
+
64
+ Thread-safe: ``submit()`` / ``run()`` may be called from any thread.
65
+
66
+ Lifecycle:
67
+ - Construct: creates the executor (no thread yet).
68
+ - ``start()``: launches the worker thread and waits for it to
69
+ CoInitialize.
70
+ - ``submit(fn)``: schedules ``fn`` on the worker; returns a Future.
71
+ - ``run(fn)``: convenience wrapper around submit+result.
72
+ - ``stop()``: signals the worker to exit, joins the thread, then
73
+ CoUninitializes.
74
+ """
75
+
76
+ def __init__(self, name: str = "SolidWorks-COM") -> None:
77
+ """Create the executor (thread not yet running).
78
+
79
+ Args:
80
+ name: Thread name for debugging / logs.
81
+ """
82
+ self._name = name
83
+ self._queue: queue.Queue[Any] = queue.Queue()
84
+ self._thread: threading.Thread | None = None
85
+ # Set by worker thread once CoInitialize succeeds, allowing submit()
86
+ # to block until the executor is truly ready.
87
+ self._ready = threading.Event()
88
+ self._stopped = threading.Event()
89
+ # Set by worker thread when CoInitialize fails so start() can join
90
+ # the thread synchronously and callers see is_alive() == False.
91
+ self._init_failed = threading.Event()
92
+
93
+ # ---- Public API ----
94
+
95
+ def start(self, timeout: float = 10.0) -> None:
96
+ """Launch the worker thread and wait until it has CoInitialized.
97
+
98
+ Idempotent: calling ``start()`` on a running executor is a no-op.
99
+
100
+ Args:
101
+ timeout: Seconds to wait for CoInitialize to complete. If it
102
+ doesn't fire in time, raises RuntimeError.
103
+
104
+ Raises:
105
+ RuntimeError: Worker didn't become ready in time.
106
+ """
107
+ if self._thread is not None and self._thread.is_alive():
108
+ return
109
+
110
+ if not PYWIN32_AVAILABLE:
111
+ raise RuntimeError("pywin32 is required for ComExecutor; not available")
112
+
113
+ self._ready.clear()
114
+ self._stopped.clear()
115
+ self._init_failed.clear()
116
+ self._thread = threading.Thread(
117
+ target=self._worker, name=self._name, daemon=True
118
+ )
119
+ self._thread.start()
120
+
121
+ if not self._ready.wait(timeout):
122
+ raise RuntimeError(
123
+ f"ComExecutor worker '{self._name}' did not "
124
+ f"initialize within {timeout}s"
125
+ )
126
+
127
+ # If CoInitialize failed the worker exits immediately after setting
128
+ # _ready. Join here so callers see is_alive() == False synchronously.
129
+ if self._init_failed.is_set():
130
+ self._thread.join(timeout)
131
+
132
+ def stop(self, timeout: float = 5.0) -> None:
133
+ """Signal the worker to exit and wait for it to join.
134
+
135
+ After ``stop()`` returns, no further ``submit()`` calls will be
136
+ serviced. Idempotent.
137
+
138
+ Args:
139
+ timeout: Seconds to wait for the worker to exit cleanly before
140
+ abandoning the join.
141
+ """
142
+ if self._thread is None or not self._thread.is_alive():
143
+ return
144
+
145
+ self._queue.put(_SHUTDOWN)
146
+ self._thread.join(timeout)
147
+ if self._thread.is_alive():
148
+ logger.warning(
149
+ f"ComExecutor worker '{self._name}' did not exit "
150
+ f"within {timeout}s; abandoning"
151
+ )
152
+ self._thread = None
153
+ self._stopped.set()
154
+
155
+ def submit(self, fn: Callable[[], T]) -> Future[T]:
156
+ """Schedule ``fn`` to run on the worker thread.
157
+
158
+ The callable receives no arguments — close over any state needed
159
+ via the enclosing scope. The return value (or exception) is
160
+ propagated through the returned ``Future``.
161
+
162
+ Args:
163
+ fn: Zero-argument callable to run on the COM thread.
164
+
165
+ Returns:
166
+ Future that will hold the result or exception.
167
+
168
+ Raises:
169
+ RuntimeError: Executor isn't running.
170
+ """
171
+ if self._thread is None or not self._thread.is_alive():
172
+ raise RuntimeError(
173
+ f"ComExecutor '{self._name}' is not running; call start() first"
174
+ )
175
+
176
+ fut: Future[T] = Future()
177
+ self._queue.put((fn, fut))
178
+ return fut
179
+
180
+ def run(self, fn: Callable[[], T], timeout: float | None = None) -> T:
181
+ """Run ``fn`` on the worker and block until the result is ready.
182
+
183
+ Convenience wrapper around ``submit()`` + ``Future.result()``.
184
+
185
+ Args:
186
+ fn: Zero-argument callable to run on the COM thread.
187
+ timeout: Seconds to wait before raising TimeoutError.
188
+
189
+ Returns:
190
+ Whatever ``fn`` returned.
191
+
192
+ Raises:
193
+ Exception: Any exception raised by ``fn``, re-raised in the caller.
194
+ TimeoutError: If ``timeout`` elapses before ``fn`` finishes.
195
+ """
196
+ return self.submit(fn).result(timeout=timeout)
197
+
198
+ # ---- Context manager ----
199
+
200
+ def __enter__(self) -> ComExecutor:
201
+ self.start()
202
+ return self
203
+
204
+ def __exit__(self, exc_type: object, exc: object, tb: object) -> None:
205
+ self.stop()
206
+
207
+ # ---- Worker ----
208
+
209
+ def _worker(self) -> None:
210
+ """Run on the dedicated thread; initialize COM, process work, cleanup.
211
+
212
+ Loop exits when ``_SHUTDOWN`` appears in the queue. Each work item
213
+ is a ``(callable, Future)`` tuple; the callable runs, and the
214
+ Future is set with either the result or the raised exception.
215
+ """
216
+ try:
217
+ pythoncom.CoInitialize()
218
+ except Exception as e:
219
+ logger.error(
220
+ f"CoInitialize failed in ComExecutor worker '{self._name}': {e!r}"
221
+ )
222
+ # Signal init failure then unblock start() so it can join this
223
+ # thread synchronously before returning.
224
+ self._init_failed.set()
225
+ self._ready.set()
226
+ return
227
+
228
+ self._ready.set()
229
+ logger.info(f"ComExecutor '{self._name}' ready")
230
+
231
+ try:
232
+ while True:
233
+ item = self._queue.get()
234
+ if item is _SHUTDOWN:
235
+ break
236
+
237
+ fn, fut = item
238
+ if not fut.set_running_or_notify_cancel():
239
+ continue
240
+
241
+ try:
242
+ result = fn()
243
+ except BaseException as e: # noqa: BLE001 — propagate everything
244
+ fut.set_exception(e)
245
+ else:
246
+ fut.set_result(result)
247
+ finally:
248
+ try:
249
+ pythoncom.CoUninitialize()
250
+ except Exception:
251
+ pass
252
+ logger.info(f"ComExecutor '{self._name}' stopped")
@@ -0,0 +1,272 @@
1
+ """Complexity analysis for routing operations between COM and VBA paths."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from dataclasses import dataclass
7
+
8
+ from pydantic import BaseModel
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class OperationProfile:
13
+ """Complexity profile metadata for an operation.
14
+
15
+ Attributes:
16
+ base_complexity (float): The base complexity value.
17
+ name (str): The name value.
18
+ vba_preferred (bool): The vba preferred value.
19
+ """
20
+
21
+ name: str
22
+ base_complexity: float
23
+ vba_preferred: bool = False
24
+
25
+
26
+ class RoutingDecision(BaseModel):
27
+ """Complexity-based routing decision.
28
+
29
+ Attributes:
30
+ complexity_score (float): The complexity score value.
31
+ operation (str): The operation value.
32
+ parameter_count (int): The parameter count value.
33
+ prefer_vba (bool): The prefer vba value.
34
+ reason (str): The reason value.
35
+ """
36
+
37
+ operation: str
38
+ parameter_count: int
39
+ complexity_score: float
40
+ prefer_vba: bool
41
+ reason: str
42
+
43
+
44
+ class ComplexityAnalyzer:
45
+ """Analyze operation complexity and recommend COM or VBA execution path.
46
+
47
+ Args:
48
+ parameter_threshold (int): The parameter threshold value. Defaults to 12.
49
+ score_threshold (float): The score threshold value. Defaults to 0.6.
50
+
51
+ Attributes:
52
+ _parameter_threshold (Any): The parameter threshold value.
53
+ _score_threshold (Any): The score threshold value.
54
+ """
55
+
56
+ def __init__(
57
+ self,
58
+ parameter_threshold: int = 12,
59
+ score_threshold: float = 0.6,
60
+ ) -> None:
61
+ """Initialize analyzer state.
62
+
63
+ Args:
64
+ parameter_threshold (int): The parameter threshold value. Defaults to 12.
65
+ score_threshold (float): The score threshold value. Defaults to 0.6.
66
+
67
+ Returns:
68
+ None: None.
69
+ """
70
+ self._parameter_threshold = max(parameter_threshold, 1)
71
+ self._score_threshold = max(min(score_threshold, 1.0), 0.1)
72
+ self._profiles: dict[str, OperationProfile] = self._default_profiles()
73
+ self._history: dict[str, dict[str, int]] = {}
74
+
75
+ def analyze(self, operation: str, payload: object) -> RoutingDecision:
76
+ """Produce a routing recommendation for an operation call.
77
+
78
+ Args:
79
+ operation (str): Callable object executed by the helper.
80
+ payload (object): The payload value.
81
+
82
+ Returns:
83
+ RoutingDecision: The result produced by the operation.
84
+ """
85
+ profile = self._profiles.get(
86
+ operation,
87
+ OperationProfile(name=operation, base_complexity=0.2, vba_preferred=False),
88
+ )
89
+ parameter_count = self._count_parameters(payload)
90
+
91
+ parameter_component = min(
92
+ parameter_count / float(self._parameter_threshold), 1.0
93
+ )
94
+ history_component = self._history_bias(operation)
95
+ complexity_score = min(
96
+ 1.0,
97
+ (parameter_component * 0.45)
98
+ + (profile.base_complexity * 0.40)
99
+ + (history_component * 0.15),
100
+ )
101
+
102
+ prefer_vba = (
103
+ parameter_count > self._parameter_threshold
104
+ or profile.vba_preferred
105
+ or complexity_score >= self._score_threshold
106
+ )
107
+
108
+ reason = (
109
+ "parameter threshold exceeded"
110
+ if parameter_count > self._parameter_threshold
111
+ else "profile prefers VBA"
112
+ if profile.vba_preferred
113
+ else "complexity score exceeded threshold"
114
+ if complexity_score >= self._score_threshold
115
+ else "COM path preferred"
116
+ )
117
+
118
+ return RoutingDecision(
119
+ operation=operation,
120
+ parameter_count=parameter_count,
121
+ complexity_score=complexity_score,
122
+ prefer_vba=prefer_vba,
123
+ reason=reason,
124
+ )
125
+
126
+ def record_result(self, operation: str, route: str, success: bool) -> None:
127
+ """Record operation outcome for future routing influence.
128
+
129
+ Args:
130
+ operation (str): Callable object executed by the helper.
131
+ route (str): The route value.
132
+ success (bool): The success value.
133
+
134
+ Returns:
135
+ None: None.
136
+ """
137
+ history = self._history.setdefault(
138
+ operation,
139
+ {
140
+ "com_success": 0,
141
+ "com_failure": 0,
142
+ "vba_success": 0,
143
+ "vba_failure": 0,
144
+ },
145
+ )
146
+ key = f"{route}_{'success' if success else 'failure'}"
147
+ if key in history:
148
+ history[key] += 1
149
+
150
+ def _history_bias(self, operation: str) -> float:
151
+ """Compute historical bias toward VBA based on COM reliability.
152
+
153
+ Args:
154
+ operation (str): Callable object executed by the helper.
155
+
156
+ Returns:
157
+ float: The computed numeric result.
158
+ """
159
+ history = self._history.get(operation)
160
+ if history is None:
161
+ return 0.0
162
+
163
+ com_success = history.get("com_success", 0)
164
+ com_failure = history.get("com_failure", 0)
165
+ com_total = com_success + com_failure
166
+ if com_total == 0:
167
+ return 0.0
168
+
169
+ failure_ratio = com_failure / float(com_total)
170
+ return max(min(failure_ratio, 1.0), 0.0)
171
+
172
+ def _count_parameters(self, payload: object) -> int:
173
+ """Count meaningful parameters in payload recursively.
174
+
175
+ Args:
176
+ payload (object): The payload value.
177
+
178
+ Returns:
179
+ int: The computed numeric result.
180
+ """
181
+ if payload is None:
182
+ return 0
183
+
184
+ if isinstance(payload, BaseModel):
185
+ return self._count_parameters(payload.model_dump(exclude_none=True))
186
+
187
+ if isinstance(payload, Mapping):
188
+ total = 0
189
+ for value in payload.values():
190
+ total += self._count_parameters(value)
191
+ return max(total, len(payload))
192
+
193
+ if isinstance(payload, (list, tuple, set)):
194
+ return sum(self._count_parameters(item) for item in payload)
195
+
196
+ return 1
197
+
198
+ def _default_profiles(self) -> dict[str, OperationProfile]:
199
+ """Return default complexity profiles for high-impact operations.
200
+
201
+ Returns:
202
+ dict[str, OperationProfile]: A dictionary containing the resulting values.
203
+ """
204
+ return {
205
+ # Modeling operations - likely to benefit from VBA routing
206
+ "create_extrusion": OperationProfile(
207
+ name="create_extrusion", base_complexity=0.55, vba_preferred=False
208
+ ),
209
+ "create_revolve": OperationProfile(
210
+ name="create_revolve", base_complexity=0.50, vba_preferred=False
211
+ ),
212
+ "create_sweep": OperationProfile(
213
+ name="create_sweep", base_complexity=0.65, vba_preferred=True
214
+ ),
215
+ "create_loft": OperationProfile(
216
+ name="create_loft", base_complexity=0.70, vba_preferred=True
217
+ ),
218
+ "create_assembly": OperationProfile(
219
+ name="create_assembly", base_complexity=0.45, vba_preferred=False
220
+ ),
221
+ "create_part": OperationProfile(
222
+ name="create_part", base_complexity=0.30, vba_preferred=False
223
+ ),
224
+ "create_drawing": OperationProfile(
225
+ name="create_drawing", base_complexity=0.50, vba_preferred=False
226
+ ),
227
+ # Sketching operations - moderate complexity
228
+ "create_sketch": OperationProfile(
229
+ name="create_sketch", base_complexity=0.25, vba_preferred=False
230
+ ),
231
+ "add_circle": OperationProfile(
232
+ name="add_circle", base_complexity=0.20, vba_preferred=False
233
+ ),
234
+ "add_rectangle": OperationProfile(
235
+ name="add_rectangle", base_complexity=0.20, vba_preferred=False
236
+ ),
237
+ "add_line": OperationProfile(
238
+ name="add_line", base_complexity=0.15, vba_preferred=False
239
+ ),
240
+ "add_arc": OperationProfile(
241
+ name="add_arc", base_complexity=0.35, vba_preferred=False
242
+ ),
243
+ "add_spline": OperationProfile(
244
+ name="add_spline", base_complexity=0.50, vba_preferred=True
245
+ ),
246
+ "add_polygon": OperationProfile(
247
+ name="add_polygon", base_complexity=0.30, vba_preferred=False
248
+ ),
249
+ "add_sketch_constraint": OperationProfile(
250
+ name="add_sketch_constraint", base_complexity=0.40, vba_preferred=False
251
+ ),
252
+ "add_sketch_dimension": OperationProfile(
253
+ name="add_sketch_dimension", base_complexity=0.30, vba_preferred=False
254
+ ),
255
+ # Assembly operations
256
+ "insert_component": OperationProfile(
257
+ name="insert_component", base_complexity=0.40, vba_preferred=False
258
+ ),
259
+ "add_mate": OperationProfile(
260
+ name="add_mate", base_complexity=0.55, vba_preferred=False
261
+ ),
262
+ # Drawing operations
263
+ "create_drawing_view": OperationProfile(
264
+ name="create_drawing_view", base_complexity=0.45, vba_preferred=False
265
+ ),
266
+ "add_drawing_annotation": OperationProfile(
267
+ name="add_drawing_annotation", base_complexity=0.35, vba_preferred=False
268
+ ),
269
+ "add_dimension": OperationProfile(
270
+ name="add_dimension", base_complexity=0.40, vba_preferred=False
271
+ ),
272
+ }