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.
- solidworks_mcp/__init__.py +57 -0
- solidworks_mcp/adapters/__init__.py +40 -0
- solidworks_mcp/adapters/base.py +1882 -0
- solidworks_mcp/adapters/circuit_breaker.py +2052 -0
- solidworks_mcp/adapters/com_executor.py +252 -0
- solidworks_mcp/adapters/complexity_analyzer.py +272 -0
- solidworks_mcp/adapters/connection_pool.py +1884 -0
- solidworks_mcp/adapters/factory.py +366 -0
- solidworks_mcp/adapters/intelligent_router.py +218 -0
- solidworks_mcp/adapters/mock_adapter.py +4016 -0
- solidworks_mcp/adapters/pywin32_adapter.py +2842 -0
- solidworks_mcp/adapters/solidworks/__init__.py +17 -0
- solidworks_mcp/adapters/solidworks/bitmap.py +180 -0
- solidworks_mcp/adapters/solidworks/com_utils.py +56 -0
- solidworks_mcp/adapters/solidworks/dimension_layout.py +753 -0
- solidworks_mcp/adapters/solidworks/documentation.py +1476 -0
- solidworks_mcp/adapters/solidworks/drawing_standard.py +1993 -0
- solidworks_mcp/adapters/solidworks/face_selection.py +392 -0
- solidworks_mcp/adapters/solidworks/features.py +3362 -0
- solidworks_mcp/adapters/solidworks/io.py +3649 -0
- solidworks_mcp/adapters/solidworks/rebuild_diagnostics.py +269 -0
- solidworks_mcp/adapters/solidworks/rebuild_inspector.py +146 -0
- solidworks_mcp/adapters/solidworks/selection.py +308 -0
- solidworks_mcp/adapters/solidworks/sketch.py +2545 -0
- solidworks_mcp/adapters/sw_feature_errors.py +66 -0
- solidworks_mcp/adapters/sw_type_info.py +317 -0
- solidworks_mcp/adapters/vba_adapter.py +318 -0
- solidworks_mcp/adapters/vba_macro_executor.py +215 -0
- solidworks_mcp/agents/__init__.py +68 -0
- solidworks_mcp/agents/design_knowledge/assembly_patterns.md +127 -0
- solidworks_mcp/agents/design_knowledge/hinges.md +118 -0
- solidworks_mcp/agents/design_knowledge/snap_fits.md +93 -0
- solidworks_mcp/agents/design_knowledge/solidworks_basics.md +3 -0
- solidworks_mcp/agents/design_knowledge/tolerancing.md +128 -0
- solidworks_mcp/agents/harness.py +216 -0
- solidworks_mcp/agents/history_db.py +1508 -0
- solidworks_mcp/agents/retrieval_index.py +164 -0
- solidworks_mcp/agents/schemas.py +165 -0
- solidworks_mcp/agents/smoke_test.py +285 -0
- solidworks_mcp/agents/soc_exporter.py +650 -0
- solidworks_mcp/agents/soc_pickup.py +332 -0
- solidworks_mcp/agents/soc_rewind.py +221 -0
- solidworks_mcp/agents/vector_rag.py +665 -0
- solidworks_mcp/cache/__init__.py +5 -0
- solidworks_mcp/cache/response_cache.py +164 -0
- solidworks_mcp/config.py +729 -0
- solidworks_mcp/exceptions.py +37 -0
- solidworks_mcp/security/__init__.py +68 -0
- solidworks_mcp/security/auth.py +128 -0
- solidworks_mcp/security/cors.py +27 -0
- solidworks_mcp/security/rate_limiting.py +90 -0
- solidworks_mcp/security/runtime.py +155 -0
- solidworks_mcp/server.py +777 -0
- solidworks_mcp/server_cli_fixed.py +120 -0
- solidworks_mcp/setup/__init__.py +1 -0
- solidworks_mcp/setup/cli.py +399 -0
- solidworks_mcp/setup/clients.py +157 -0
- solidworks_mcp/setup/config_file.py +230 -0
- solidworks_mcp/setup/handshake.py +202 -0
- solidworks_mcp/setup/launcher.py +102 -0
- solidworks_mcp/setup/legacy.py +100 -0
- solidworks_mcp/setup/registration.py +193 -0
- solidworks_mcp/setup/solidworks.py +49 -0
- solidworks_mcp/tools/__init__.py +64 -0
- solidworks_mcp/tools/analysis.py +723 -0
- solidworks_mcp/tools/automation.py +578 -0
- solidworks_mcp/tools/docs_discovery.py +1476 -0
- solidworks_mcp/tools/drawing.py +1015 -0
- solidworks_mcp/tools/drawing_analysis.py +456 -0
- solidworks_mcp/tools/drawing_automation.py +627 -0
- solidworks_mcp/tools/engineering_data.py +466 -0
- solidworks_mcp/tools/error_classifier.py +232 -0
- solidworks_mcp/tools/export.py +833 -0
- solidworks_mcp/tools/file_facts.py +40 -0
- solidworks_mcp/tools/file_management.py +1473 -0
- solidworks_mcp/tools/input_compat.py +17 -0
- solidworks_mcp/tools/macro_recording.py +464 -0
- solidworks_mcp/tools/modeling.py +2360 -0
- solidworks_mcp/tools/sketching.py +1422 -0
- solidworks_mcp/tools/template_management.py +367 -0
- solidworks_mcp/tools/tool_boundary.py +280 -0
- solidworks_mcp/tools/vba_generation.py +1145 -0
- solidworks_mcp/ui/__init__.py +9 -0
- solidworks_mcp/ui/local_llm.py +725 -0
- solidworks_mcp/ui/routers/__init__.py +10 -0
- solidworks_mcp/ui/routers/checkpoint.py +24 -0
- solidworks_mcp/ui/routers/docs.py +47 -0
- solidworks_mcp/ui/routers/llm.py +83 -0
- solidworks_mcp/ui/routers/local_model.py +69 -0
- solidworks_mcp/ui/routers/model.py +75 -0
- solidworks_mcp/ui/routers/preview.py +38 -0
- solidworks_mcp/ui/routers/session.py +161 -0
- solidworks_mcp/ui/routers/viewer.py +154 -0
- solidworks_mcp/ui/schemas.py +502 -0
- solidworks_mcp/ui/server.py +298 -0
- solidworks_mcp/ui/service.py +481 -0
- solidworks_mcp/ui/services/__init__.py +136 -0
- solidworks_mcp/ui/services/_utils.py +958 -0
- solidworks_mcp/ui/services/checkpoint_service.py +1110 -0
- solidworks_mcp/ui/services/docs_service.py +282 -0
- solidworks_mcp/ui/services/llm_service.py +956 -0
- solidworks_mcp/ui/services/model_service.py +459 -0
- solidworks_mcp/ui/services/parameter_repair_service.py +314 -0
- solidworks_mcp/ui/services/preview_service.py +489 -0
- solidworks_mcp/ui/services/session_service.py +1389 -0
- solidworks_mcp/utils/__init__.py +9 -0
- solidworks_mcp/utils/feature_tree_classifier.py +342 -0
- solidworks_mcp/utils/logging.py +76 -0
- solidworks_mcp/utils/validation.py +77 -0
- solidworks_mcp/version.py +8 -0
- solidworks_mcp_python-1.5.0.dist-info/METADATA +410 -0
- solidworks_mcp_python-1.5.0.dist-info/RECORD +115 -0
- solidworks_mcp_python-1.5.0.dist-info/WHEEL +4 -0
- solidworks_mcp_python-1.5.0.dist-info/entry_points.txt +3 -0
- solidworks_mcp_python-1.5.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""Docs context fetching and RAG ingestion for the Prefab CAD dashboard.
|
|
2
|
+
|
|
3
|
+
Responsibilities (Single Responsibility principle):
|
|
4
|
+
- Fetch and filter docs from the MCP docs endpoint (``fetch_docs_context``).
|
|
5
|
+
- Ingest local files or URLs into the simple retrieval index (``ingest_reference_source``).
|
|
6
|
+
|
|
7
|
+
Does NOT own: LLM calls, preview export, session state mutation beyond metadata merges.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
from urllib.parse import urlparse
|
|
16
|
+
from urllib.request import Request, urlopen
|
|
17
|
+
|
|
18
|
+
from loguru import logger
|
|
19
|
+
|
|
20
|
+
from ...agents.history_db import insert_evidence_link, insert_tool_call_record
|
|
21
|
+
from ...agents.retrieval_index import _chunk_text
|
|
22
|
+
from ._utils import (
|
|
23
|
+
DEFAULT_API_ORIGIN,
|
|
24
|
+
DEFAULT_RAG_DIR,
|
|
25
|
+
HTMLTextExtractor,
|
|
26
|
+
filter_docs_text,
|
|
27
|
+
is_url_reference,
|
|
28
|
+
merge_metadata,
|
|
29
|
+
persist_ui_action,
|
|
30
|
+
read_reference_source,
|
|
31
|
+
read_reference_url,
|
|
32
|
+
sanitize_ui_text,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
# Public API
|
|
37
|
+
# ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def fetch_docs_context(
|
|
41
|
+
session_id: str,
|
|
42
|
+
*,
|
|
43
|
+
docs_query: str = "",
|
|
44
|
+
db_path: Path | None = None,
|
|
45
|
+
api_origin: str = DEFAULT_API_ORIGIN,
|
|
46
|
+
) -> dict[str, Any]:
|
|
47
|
+
"""Fetch docs text from the ``/docs`` endpoint and store a filtered context snippet.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
session_id: Dashboard session identifier.
|
|
51
|
+
docs_query: Keyword(s) to filter the docs text by.
|
|
52
|
+
db_path: Optional override for the SQLite database path.
|
|
53
|
+
api_origin: Base URL of the running FastAPI server.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Full dashboard state payload.
|
|
57
|
+
"""
|
|
58
|
+
from .session_service import ( # noqa: PLC0415
|
|
59
|
+
build_dashboard_state,
|
|
60
|
+
ensure_dashboard_session,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
ensure_dashboard_session(session_id, db_path=db_path)
|
|
64
|
+
docs_url = f"{api_origin}/docs"
|
|
65
|
+
query_text = sanitize_ui_text(docs_query, "solidworks workflow")
|
|
66
|
+
if urlparse(docs_url).scheme not in {"http", "https"}:
|
|
67
|
+
raise ValueError(f"Disallowed URL scheme in docs endpoint: {docs_url!r}")
|
|
68
|
+
try:
|
|
69
|
+
request = Request(docs_url, headers={"User-Agent": "solidworks-mcp-ui/1.0"})
|
|
70
|
+
with urlopen(request, timeout=8) as response: # nosec B310
|
|
71
|
+
html = response.read().decode("utf-8", errors="ignore")
|
|
72
|
+
extractor = HTMLTextExtractor()
|
|
73
|
+
extractor.feed(html)
|
|
74
|
+
snippet = filter_docs_text(extractor.text(), query_text)
|
|
75
|
+
persist_ui_action(
|
|
76
|
+
session_id,
|
|
77
|
+
tool_name="ui.docs.fetch",
|
|
78
|
+
db_path=db_path,
|
|
79
|
+
metadata_updates={
|
|
80
|
+
"docs_query": query_text,
|
|
81
|
+
"docs_context_text": snippet,
|
|
82
|
+
"latest_message": "Docs context updated from MCP docs endpoint.",
|
|
83
|
+
"latest_error_text": "",
|
|
84
|
+
"remediation_hint": "",
|
|
85
|
+
},
|
|
86
|
+
input_payload={"query": query_text, "url": docs_url},
|
|
87
|
+
output_payload={"chars": len(snippet)},
|
|
88
|
+
)
|
|
89
|
+
except Exception as exc:
|
|
90
|
+
logger.exception("[ui.fetch_docs_context] failed session_id={}", session_id)
|
|
91
|
+
merge_metadata(
|
|
92
|
+
session_id,
|
|
93
|
+
db_path=db_path,
|
|
94
|
+
docs_query=query_text,
|
|
95
|
+
docs_context_text="",
|
|
96
|
+
latest_error_text=str(exc),
|
|
97
|
+
remediation_hint="Verify the /docs endpoint is reachable, then retry docs refresh.",
|
|
98
|
+
)
|
|
99
|
+
return build_dashboard_state(session_id, db_path=db_path, api_origin=api_origin)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def ingest_reference_source(
|
|
103
|
+
session_id: str,
|
|
104
|
+
*,
|
|
105
|
+
source_path: str,
|
|
106
|
+
namespace: str,
|
|
107
|
+
chunk_size: int = 1200,
|
|
108
|
+
overlap: int = 200,
|
|
109
|
+
db_path: Path | None = None,
|
|
110
|
+
) -> dict[str, Any]:
|
|
111
|
+
"""Ingest a local file or URL into the simple local retrieval index.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
session_id: Dashboard session identifier.
|
|
115
|
+
source_path: Absolute file path or http/https URL.
|
|
116
|
+
namespace: Namespace key that isolates this index from others.
|
|
117
|
+
chunk_size: Maximum characters per chunk.
|
|
118
|
+
overlap: Overlapping characters between adjacent chunks.
|
|
119
|
+
db_path: Optional override for the SQLite database path.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Full dashboard state payload.
|
|
123
|
+
"""
|
|
124
|
+
from .session_service import ( # noqa: PLC0415
|
|
125
|
+
build_dashboard_state,
|
|
126
|
+
ensure_dashboard_session,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
ensure_dashboard_session(session_id, db_path=db_path)
|
|
130
|
+
source_reference = (source_path or "").strip()
|
|
131
|
+
resolved_namespace = (
|
|
132
|
+
namespace or "engineering-reference"
|
|
133
|
+
).strip() or "engineering-reference"
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
if is_url_reference(source_reference):
|
|
137
|
+
source_identifier = source_reference
|
|
138
|
+
source_text, source_label = read_reference_url(source_reference)
|
|
139
|
+
else:
|
|
140
|
+
resolved_source = Path(source_reference).expanduser()
|
|
141
|
+
if not resolved_source.exists():
|
|
142
|
+
merge_metadata(
|
|
143
|
+
session_id,
|
|
144
|
+
db_path=db_path,
|
|
145
|
+
rag_source_path=str(resolved_source),
|
|
146
|
+
rag_namespace=resolved_namespace,
|
|
147
|
+
rag_status="Reference source path was not found.",
|
|
148
|
+
latest_error_text=f"Missing reference source: {resolved_source}",
|
|
149
|
+
remediation_hint=(
|
|
150
|
+
"Provide an absolute path or an http/https URL for a PDF, "
|
|
151
|
+
"markdown, text, or HTML source."
|
|
152
|
+
),
|
|
153
|
+
)
|
|
154
|
+
return build_dashboard_state(session_id, db_path=db_path)
|
|
155
|
+
source_identifier = str(resolved_source.resolve())
|
|
156
|
+
source_label = resolved_source.name
|
|
157
|
+
source_text = read_reference_source(resolved_source)
|
|
158
|
+
|
|
159
|
+
chunks = _chunk_text(source_text, chunk_size=chunk_size, overlap=overlap)
|
|
160
|
+
output_path = DEFAULT_RAG_DIR / f"{resolved_namespace}.json"
|
|
161
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
162
|
+
payload: dict[str, Any] = {
|
|
163
|
+
"version": "1.0",
|
|
164
|
+
"namespace": resolved_namespace,
|
|
165
|
+
"source_location": source_identifier,
|
|
166
|
+
"chunk_count": len(chunks),
|
|
167
|
+
"chunks": [
|
|
168
|
+
{
|
|
169
|
+
"id": f"{resolved_namespace}-{index}",
|
|
170
|
+
"source": source_identifier,
|
|
171
|
+
"text": chunk,
|
|
172
|
+
}
|
|
173
|
+
for index, chunk in enumerate(chunks, start=1)
|
|
174
|
+
],
|
|
175
|
+
}
|
|
176
|
+
output_path.write_text(
|
|
177
|
+
json.dumps(payload, indent=2, ensure_ascii=True), encoding="utf-8"
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# --- FAISS vector index (best-effort; skipped if optional deps missing) ---
|
|
181
|
+
try:
|
|
182
|
+
from ...agents.vector_rag import VectorRAGIndex # noqa: PLC0415
|
|
183
|
+
|
|
184
|
+
idx = VectorRAGIndex.load(
|
|
185
|
+
namespace=resolved_namespace, rag_dir=DEFAULT_RAG_DIR
|
|
186
|
+
)
|
|
187
|
+
for chunk in payload["chunks"]:
|
|
188
|
+
idx.ingest_text(
|
|
189
|
+
chunk["text"], source=source_identifier, tags=[resolved_namespace]
|
|
190
|
+
)
|
|
191
|
+
idx.save()
|
|
192
|
+
logger.info(
|
|
193
|
+
"[ui.ingest_reference_source] FAISS index updated namespace={} chunks={}",
|
|
194
|
+
resolved_namespace,
|
|
195
|
+
len(chunks),
|
|
196
|
+
)
|
|
197
|
+
except ImportError:
|
|
198
|
+
logger.debug(
|
|
199
|
+
"[ui.ingest_reference_source] FAISS not available; skipping vector index"
|
|
200
|
+
)
|
|
201
|
+
except Exception as faiss_exc:
|
|
202
|
+
logger.warning(
|
|
203
|
+
"[ui.ingest_reference_source] FAISS indexing failed (non-fatal): {}",
|
|
204
|
+
faiss_exc,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
insert_evidence_link(
|
|
208
|
+
session_id=session_id,
|
|
209
|
+
source_type="rag_ingest",
|
|
210
|
+
source_id=source_identifier,
|
|
211
|
+
relevance_score=0.88,
|
|
212
|
+
rationale=f"Ingested {len(chunks)} chunk(s) into namespace '{resolved_namespace}'.",
|
|
213
|
+
payload_json=json.dumps(
|
|
214
|
+
{
|
|
215
|
+
"namespace": resolved_namespace,
|
|
216
|
+
"index_path": str(output_path.resolve()),
|
|
217
|
+
"chunk_count": len(chunks),
|
|
218
|
+
},
|
|
219
|
+
ensure_ascii=True,
|
|
220
|
+
),
|
|
221
|
+
db_path=db_path,
|
|
222
|
+
)
|
|
223
|
+
merge_metadata(
|
|
224
|
+
session_id,
|
|
225
|
+
db_path=db_path,
|
|
226
|
+
rag_source_path=source_identifier,
|
|
227
|
+
rag_namespace=resolved_namespace,
|
|
228
|
+
rag_status=f"Ingested {len(chunks)} chunk(s) from {source_label}.",
|
|
229
|
+
rag_index_path=str(output_path.resolve()),
|
|
230
|
+
rag_chunk_count=len(chunks),
|
|
231
|
+
rag_provenance_text=(
|
|
232
|
+
f"Namespace {resolved_namespace} | source {source_label} | chunks {len(chunks)}"
|
|
233
|
+
),
|
|
234
|
+
latest_message=f"Reference source {source_label} ingested for retrieval.",
|
|
235
|
+
latest_error_text="",
|
|
236
|
+
remediation_hint="",
|
|
237
|
+
)
|
|
238
|
+
insert_tool_call_record(
|
|
239
|
+
session_id=session_id,
|
|
240
|
+
tool_name="ui.ingest_reference_source",
|
|
241
|
+
input_json=json.dumps(
|
|
242
|
+
{
|
|
243
|
+
"source_path": source_identifier,
|
|
244
|
+
"namespace": resolved_namespace,
|
|
245
|
+
"chunk_size": chunk_size,
|
|
246
|
+
"overlap": overlap,
|
|
247
|
+
},
|
|
248
|
+
ensure_ascii=True,
|
|
249
|
+
),
|
|
250
|
+
output_json=json.dumps(
|
|
251
|
+
{"index_path": str(output_path.resolve()), "chunk_count": len(chunks)},
|
|
252
|
+
ensure_ascii=True,
|
|
253
|
+
),
|
|
254
|
+
success=True,
|
|
255
|
+
db_path=db_path,
|
|
256
|
+
)
|
|
257
|
+
except Exception as exc:
|
|
258
|
+
merge_metadata(
|
|
259
|
+
session_id,
|
|
260
|
+
db_path=db_path,
|
|
261
|
+
rag_source_path=source_reference,
|
|
262
|
+
rag_namespace=resolved_namespace,
|
|
263
|
+
rag_status="Reference ingestion failed.",
|
|
264
|
+
latest_error_text=str(exc),
|
|
265
|
+
remediation_hint=(
|
|
266
|
+
"Use a readable local file or http/https URL and ensure optional "
|
|
267
|
+
"PDF dependencies are installed."
|
|
268
|
+
),
|
|
269
|
+
)
|
|
270
|
+
insert_tool_call_record(
|
|
271
|
+
session_id=session_id,
|
|
272
|
+
tool_name="ui.ingest_reference_source",
|
|
273
|
+
input_json=json.dumps(
|
|
274
|
+
{"source_path": source_reference, "namespace": resolved_namespace},
|
|
275
|
+
ensure_ascii=True,
|
|
276
|
+
),
|
|
277
|
+
output_json=json.dumps({"error": str(exc)}, ensure_ascii=True),
|
|
278
|
+
success=False,
|
|
279
|
+
db_path=db_path,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
return build_dashboard_state(session_id, db_path=db_path)
|