python-hwpx-automation 6.0.3__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 (217) hide show
  1. hwpx_automation/__init__.py +61 -0
  2. hwpx_automation/__init__.pyi +27 -0
  3. hwpx_automation/__main__.py +8 -0
  4. hwpx_automation/agent_document.py +392 -0
  5. hwpx_automation/api.py +136 -0
  6. hwpx_automation/blind_eval.py +407 -0
  7. hwpx_automation/capabilities.py +110 -0
  8. hwpx_automation/compat.py +48 -0
  9. hwpx_automation/configuration.py +60 -0
  10. hwpx_automation/core/__init__.py +2 -0
  11. hwpx_automation/core/content.py +762 -0
  12. hwpx_automation/core/context.py +111 -0
  13. hwpx_automation/core/diff.py +53 -0
  14. hwpx_automation/core/document.py +37 -0
  15. hwpx_automation/core/formatting.py +513 -0
  16. hwpx_automation/core/handles.py +24 -0
  17. hwpx_automation/core/locations.py +205 -0
  18. hwpx_automation/core/locator.py +162 -0
  19. hwpx_automation/core/plan.py +680 -0
  20. hwpx_automation/core/resources.py +42 -0
  21. hwpx_automation/core/search.py +296 -0
  22. hwpx_automation/core/transactions.py +434 -0
  23. hwpx_automation/core/txn.py +48 -0
  24. hwpx_automation/document_state.py +95 -0
  25. hwpx_automation/errors.py +174 -0
  26. hwpx_automation/execution_lock.py +15 -0
  27. hwpx_automation/fastmcp_adapter.py +672 -0
  28. hwpx_automation/form_fill.py +1177 -0
  29. hwpx_automation/form_output_models.py +223 -0
  30. hwpx_automation/handlers/__init__.py +2 -0
  31. hwpx_automation/handlers/_shared.py +377 -0
  32. hwpx_automation/handlers/agent_document.py +257 -0
  33. hwpx_automation/handlers/authoring.py +750 -0
  34. hwpx_automation/handlers/content_edit.py +1078 -0
  35. hwpx_automation/handlers/form_fill.py +607 -0
  36. hwpx_automation/handlers/layout_style.py +660 -0
  37. hwpx_automation/handlers/quality_render.py +566 -0
  38. hwpx_automation/handlers/read_export.py +1295 -0
  39. hwpx_automation/handlers/specialized.py +624 -0
  40. hwpx_automation/handlers/tracked_changes.py +589 -0
  41. hwpx_automation/handlers/workflow.py +105 -0
  42. hwpx_automation/hwp_converter.py +227 -0
  43. hwpx_automation/hwp_support.py +94 -0
  44. hwpx_automation/hwpx_ops.py +1439 -0
  45. hwpx_automation/identity.json +263 -0
  46. hwpx_automation/identity.py +18 -0
  47. hwpx_automation/ingest_adapters.py +85 -0
  48. hwpx_automation/markdown_plan.py +216 -0
  49. hwpx_automation/mcp_cli.py +29 -0
  50. hwpx_automation/metadata/tools_meta.py +40 -0
  51. hwpx_automation/mixed_form.py +3007 -0
  52. hwpx_automation/mutation_models.py +401 -0
  53. hwpx_automation/network_policy.py +232 -0
  54. hwpx_automation/office/__init__.py +14 -0
  55. hwpx_automation/office/agent/__init__.py +125 -0
  56. hwpx_automation/office/agent/_batch_verification.py +383 -0
  57. hwpx_automation/office/agent/blueprint/__init__.py +58 -0
  58. hwpx_automation/office/agent/blueprint/bundle.py +282 -0
  59. hwpx_automation/office/agent/blueprint/catalog.py +136 -0
  60. hwpx_automation/office/agent/blueprint/dump.py +520 -0
  61. hwpx_automation/office/agent/blueprint/mapping.py +312 -0
  62. hwpx_automation/office/agent/blueprint/model.py +722 -0
  63. hwpx_automation/office/agent/blueprint/native.py +621 -0
  64. hwpx_automation/office/agent/blueprint/replay.py +622 -0
  65. hwpx_automation/office/agent/catalog.py +252 -0
  66. hwpx_automation/office/agent/cli.py +647 -0
  67. hwpx_automation/office/agent/commands.py +1383 -0
  68. hwpx_automation/office/agent/document.py +801 -0
  69. hwpx_automation/office/agent/form_plan.py +1760 -0
  70. hwpx_automation/office/agent/model.py +808 -0
  71. hwpx_automation/office/agent/path.py +155 -0
  72. hwpx_automation/office/agent/query.py +230 -0
  73. hwpx_automation/office/agent/story.py +207 -0
  74. hwpx_automation/office/authoring/__init__.py +3542 -0
  75. hwpx_automation/office/authoring/advanced_generators.py +154 -0
  76. hwpx_automation/office/authoring/builder/__init__.py +52 -0
  77. hwpx_automation/office/authoring/builder/core.py +996 -0
  78. hwpx_automation/office/authoring/builder/report.py +195 -0
  79. hwpx_automation/office/authoring/design/__init__.py +30 -0
  80. hwpx_automation/office/authoring/design/_support.py +144 -0
  81. hwpx_automation/office/authoring/design/composer.py +282 -0
  82. hwpx_automation/office/authoring/design/harvest.py +305 -0
  83. hwpx_automation/office/authoring/design/plan.py +69 -0
  84. hwpx_automation/office/authoring/design/profile.py +88 -0
  85. hwpx_automation/office/authoring/design/profiles/application_form/fragments/body.xml +1 -0
  86. hwpx_automation/office/authoring/design/profiles/application_form/fragments/heading.xml +1 -0
  87. hwpx_automation/office/authoring/design/profiles/application_form/fragments/info_table.xml +1 -0
  88. hwpx_automation/office/authoring/design/profiles/application_form/fragments/title.xml +1 -0
  89. hwpx_automation/office/authoring/design/profiles/application_form/profile.json +25 -0
  90. hwpx_automation/office/authoring/design/profiles/application_form/template.hwpx +0 -0
  91. hwpx_automation/office/authoring/design/profiles/home_notice/fragments/body.xml +1 -0
  92. hwpx_automation/office/authoring/design/profiles/home_notice/fragments/heading.xml +1 -0
  93. hwpx_automation/office/authoring/design/profiles/home_notice/fragments/title.xml +1 -0
  94. hwpx_automation/office/authoring/design/profiles/home_notice/profile.json +24 -0
  95. hwpx_automation/office/authoring/design/profiles/home_notice/template.hwpx +0 -0
  96. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/body.xml +1 -0
  97. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/heading.xml +1 -0
  98. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/info_table.xml +1 -0
  99. hwpx_automation/office/authoring/design/profiles/official_notice/fragments/title.xml +1 -0
  100. hwpx_automation/office/authoring/design/profiles/official_notice/profile.json +25 -0
  101. hwpx_automation/office/authoring/design/profiles/official_notice/template.hwpx +0 -0
  102. hwpx_automation/office/authoring/design/profiles/report/fragments/body.xml +1 -0
  103. hwpx_automation/office/authoring/design/profiles/report/fragments/heading.xml +1 -0
  104. hwpx_automation/office/authoring/design/profiles/report/fragments/info_table.xml +1 -0
  105. hwpx_automation/office/authoring/design/profiles/report/fragments/title.xml +1 -0
  106. hwpx_automation/office/authoring/design/profiles/report/profile.json +25 -0
  107. hwpx_automation/office/authoring/design/profiles/report/template.hwpx +0 -0
  108. hwpx_automation/office/authoring/design/validator.py +107 -0
  109. hwpx_automation/office/authoring/presets/__init__.py +22 -0
  110. hwpx_automation/office/authoring/presets/proposal.py +538 -0
  111. hwpx_automation/office/authoring/report_parser.py +141 -0
  112. hwpx_automation/office/authoring/style_profile.py +437 -0
  113. hwpx_automation/office/authoring/template_analyzer.py +657 -0
  114. hwpx_automation/office/compliance/__init__.py +38 -0
  115. hwpx_automation/office/compliance/official_lint.py +478 -0
  116. hwpx_automation/office/compliance/pii.py +388 -0
  117. hwpx_automation/office/document_ops/__init__.py +13 -0
  118. hwpx_automation/office/document_ops/comparison.py +62 -0
  119. hwpx_automation/office/document_ops/mail_merge.py +73 -0
  120. hwpx_automation/office/document_ops/redline.py +35 -0
  121. hwpx_automation/office/evalplan/__init__.py +36 -0
  122. hwpx_automation/office/evalplan/runtime.py +2762 -0
  123. hwpx_automation/office/exam/__init__.py +44 -0
  124. hwpx_automation/office/exam/compose.py +282 -0
  125. hwpx_automation/office/exam/ir.py +44 -0
  126. hwpx_automation/office/exam/measure.py +163 -0
  127. hwpx_automation/office/exam/parser.py +150 -0
  128. hwpx_automation/office/exam/profile.py +123 -0
  129. hwpx_automation/office/form_fill/__init__.py +66 -0
  130. hwpx_automation/office/form_fill/classification.py +108 -0
  131. hwpx_automation/office/form_fill/fill_residue.py +242 -0
  132. hwpx_automation/office/form_fill/fit/__init__.py +36 -0
  133. hwpx_automation/office/form_fill/fit/apply.py +24 -0
  134. hwpx_automation/office/form_fill/fit/engine.py +24 -0
  135. hwpx_automation/office/form_fill/fit/measure.py +50 -0
  136. hwpx_automation/office/form_fill/fit/policy.py +28 -0
  137. hwpx_automation/office/form_fill/fit/report.py +28 -0
  138. hwpx_automation/office/form_fill/fit/seal.py +457 -0
  139. hwpx_automation/office/form_fill/fit/wordbox.py +1343 -0
  140. hwpx_automation/office/form_fill/guidance.py +704 -0
  141. hwpx_automation/office/form_fill/quality.py +961 -0
  142. hwpx_automation/office/form_fill/split_run.py +333 -0
  143. hwpx_automation/office/form_fill/template_formfit.py +656 -0
  144. hwpx_automation/office/house_style/__init__.py +196 -0
  145. hwpx_automation/office/house_style/composition.py +68 -0
  146. hwpx_automation/office/house_style/data/bank.json +625 -0
  147. hwpx_automation/office/house_style/data/genres.json +43 -0
  148. hwpx_automation/office/quality/__init__.py +14 -0
  149. hwpx_automation/office/quality/page_guard.py +277 -0
  150. hwpx_automation/office/rendering/__init__.py +145 -0
  151. hwpx_automation/office/rendering/_hancom_open_rate.ps1 +374 -0
  152. hwpx_automation/office/rendering/_refresh_hwpx_mac.applescript +162 -0
  153. hwpx_automation/office/rendering/_render_hwpx.ps1 +72 -0
  154. hwpx_automation/office/rendering/_render_hwpx_mac.applescript +249 -0
  155. hwpx_automation/office/rendering/block_splits.py +76 -0
  156. hwpx_automation/office/rendering/detectors.py +151 -0
  157. hwpx_automation/office/rendering/diff.py +153 -0
  158. hwpx_automation/office/rendering/fixture_corpus.py +215 -0
  159. hwpx_automation/office/rendering/oracle.py +909 -0
  160. hwpx_automation/office/rendering/page_qa.py +245 -0
  161. hwpx_automation/office/rendering/qa_contracts.py +293 -0
  162. hwpx_automation/office/rendering/qa_metrics.py +241 -0
  163. hwpx_automation/office/rendering/worker.py +290 -0
  164. hwpx_automation/office/utilities/__init__.py +12 -0
  165. hwpx_automation/office/utilities/table_compute.py +477 -0
  166. hwpx_automation/ops_services/__init__.py +1 -0
  167. hwpx_automation/ops_services/_border_fill.py +283 -0
  168. hwpx_automation/ops_services/composition.py +55 -0
  169. hwpx_automation/ops_services/content_layout.py +322 -0
  170. hwpx_automation/ops_services/context.py +213 -0
  171. hwpx_automation/ops_services/form_fields.py +557 -0
  172. hwpx_automation/ops_services/media.py +178 -0
  173. hwpx_automation/ops_services/memo_style.py +477 -0
  174. hwpx_automation/ops_services/package_validation.py +166 -0
  175. hwpx_automation/ops_services/planning.py +201 -0
  176. hwpx_automation/ops_services/preview_export.py +585 -0
  177. hwpx_automation/ops_services/read_query.py +601 -0
  178. hwpx_automation/ops_services/save_policy.py +604 -0
  179. hwpx_automation/ops_services/tables.py +539 -0
  180. hwpx_automation/ops_services/transactions.py +616 -0
  181. hwpx_automation/preview_output_models.py +69 -0
  182. hwpx_automation/public-modules.json +206 -0
  183. hwpx_automation/py.typed +1 -0
  184. hwpx_automation/quality.py +351 -0
  185. hwpx_automation/quality_generation.py +725 -0
  186. hwpx_automation/runtime.py +321 -0
  187. hwpx_automation/runtime_services.py +100 -0
  188. hwpx_automation/server.py +259 -0
  189. hwpx_automation/storage.py +747 -0
  190. hwpx_automation/tool_bindings.py +170 -0
  191. hwpx_automation/tool_contract.py +982 -0
  192. hwpx_automation/upstream.py +755 -0
  193. hwpx_automation/utils/__init__.py +2 -0
  194. hwpx_automation/utils/helpers.py +29 -0
  195. hwpx_automation/visual_qa.py +667 -0
  196. hwpx_automation/workflow/__init__.py +55 -0
  197. hwpx_automation/workflow/adapters.py +482 -0
  198. hwpx_automation/workflow/dispatcher.py +213 -0
  199. hwpx_automation/workflow/models.py +243 -0
  200. hwpx_automation/workflow/policy.py +198 -0
  201. hwpx_automation/workflow/render_contracts.py +173 -0
  202. hwpx_automation/workflow/render_metrics.py +196 -0
  203. hwpx_automation/workflow/render_queue.py +482 -0
  204. hwpx_automation/workflow/render_security.py +172 -0
  205. hwpx_automation/workflow/render_transport.py +369 -0
  206. hwpx_automation/workflow/rendering.py +206 -0
  207. hwpx_automation/workflow/service.py +758 -0
  208. hwpx_automation/workflow/state_machine.py +65 -0
  209. hwpx_automation/workflow/store.py +747 -0
  210. hwpx_automation/workspace.py +1694 -0
  211. python_hwpx_automation-6.0.3.dist-info/METADATA +279 -0
  212. python_hwpx_automation-6.0.3.dist-info/RECORD +217 -0
  213. python_hwpx_automation-6.0.3.dist-info/WHEEL +5 -0
  214. python_hwpx_automation-6.0.3.dist-info/entry_points.txt +3 -0
  215. python_hwpx_automation-6.0.3.dist-info/licenses/LICENSE +178 -0
  216. python_hwpx_automation-6.0.3.dist-info/licenses/NOTICE +14 -0
  217. python_hwpx_automation-6.0.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,174 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """공통 에러 모델과 MCP 에러 변환 유틸리티."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Any, Dict, Literal, Optional
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field
9
+
10
+ ErrorCategory = Literal[
11
+ "validation",
12
+ "permission",
13
+ "not_found",
14
+ "capability",
15
+ "document",
16
+ "network",
17
+ "internal",
18
+ ]
19
+
20
+
21
+ class CommonErrorModel(BaseModel):
22
+ """클라이언트가 일관되게 처리할 수 있는 공통 에러 페이로드."""
23
+
24
+ model_config = ConfigDict(populate_by_name=True, extra="forbid")
25
+
26
+ schema_version: Literal["hwpx.mcp-error/v1"] = Field(
27
+ default="hwpx.mcp-error/v1", alias="schemaVersion"
28
+ )
29
+ code: str
30
+ category: ErrorCategory
31
+ message: str
32
+ retryable: bool = False
33
+ details: Optional[Dict[str, Any]] = None
34
+ hint: Optional[str] = None
35
+ suggestion: Optional[str] = None
36
+
37
+
38
+ ERROR_CODE_TO_MCP_CODE: dict[str, int] = {
39
+ "DOCUMENT_NOT_FOUND": -32044,
40
+ "PERMISSION_DENIED": -32043,
41
+ "TABLE_INDEX_OUT_OF_RANGE": -32042,
42
+ "PARAGRAPH_INDEX_OUT_OF_RANGE": -32042,
43
+ "PIPELINE_ERROR": -32041,
44
+ "WORKSPACE_OUTSIDE_ROOT": -32043,
45
+ "WORKSPACE_SYMLINK_ESCAPE": -32043,
46
+ "WORKSPACE_ROOT_INVALID": -32043,
47
+ "WORKSPACE_PATH_INVALID": -32602,
48
+ "INVALID_ARGUMENT": -32602,
49
+ "NETWORK_DESTINATION_DENIED": -32040,
50
+ }
51
+
52
+
53
+ DEFAULT_MCP_ERROR_CODE = -32000
54
+
55
+
56
+ DEFAULT_ERROR_SUGGESTIONS: dict[str, str] = {
57
+ "AMBIGUOUS_TARGET": "검색 조건을 더 구체화하거나 limit=1로 미리보기를 다시 생성하세요.",
58
+ "BYTE_PATCH_OPEN_SAFETY_FAILED": "반환된 openSafety 진단을 확인하고 일반 저장/복구 경로로 다시 생성하세요.",
59
+ "CAPABILITY_SKEW": "core/automation/plugin ToolSpec 계약 불일치로 쓰기가 차단되었습니다. mcp_server_health의 최소 버전과 contract hash에 맞춰 다시 설치한 뒤 호스트를 재시작하세요.",
60
+ "FIELD_OVERFLOW": "값이 칸에 넘칩니다. fitPolicy(mode=wrap_then_shrink/shrink/truncate_with_report) 또는 overflow=warn으로 다시 채우거나 값을 줄이세요. details.visualComplete.suggestedRetry 참고.",
61
+ "STALE_LINESEG_DETECTED": "오래된 lineseg 레이아웃 캐시가 남았습니다. 해당 문단을 다시 편집해 캐시를 무효화한 뒤 저장하세요.",
62
+ "VISUAL_COMPLETE_FAILED": "한컴 렌더에서 겹침/넘침 등 시각 결함이 감지되었습니다. details.visualComplete를 확인하고 수정 후 다시 저장하세요.",
63
+ "REQUIRED_FIELD_MISSING": "필수 폼 필드가 비어 있습니다. 값을 채운 뒤 다시 저장하세요.",
64
+ "TABLE_STRUCTURE_INVALID": "표 구조가 한컴 필수 요소를 누락했습니다. repair_hwpx로 복구하거나 표를 다시 생성하세요.",
65
+ "BYTE_PATCH_UNAVAILABLE": "설치된 python-hwpx 버전을 확인한 뒤 플러그인을 다시 설치하거나 일반 편집 도구를 사용하세요.",
66
+ "CONFLICTING_TARGETS": "동일 범위를 겹쳐 수정하지 않도록 edit 목록을 분리해 다시 실행하세요.",
67
+ "DOCUMENT_LOCATOR_REQUIRED": "path 또는 handleId 중 하나를 지정한 뒤 같은 작업을 다시 호출하세요.",
68
+ "DOCUMENT_NOT_FOUND": "문서 경로가 허용된 workspace root 안에 존재하는지 확인하고 절대/상대 경로를 다시 전달하세요.",
69
+ "DOCUMENT_OPEN_FAILED": "파일이 유효한 HWPX인지 확인하고 repair_hwpx로 복구한 뒤 다시 여세요.",
70
+ "DOCUMENT_SAVE_FAILED": "출력 경로의 쓰기 권한과 남은 디스크 공간을 확인한 뒤 다시 저장하세요.",
71
+ "EMPTY_MATCH": "찾을 텍스트나 앵커 조건을 실제 문서 내용에 맞게 수정하세요.",
72
+ "HWP_CONVERSION_FAILED": "원본 HWP가 손상되지 않았는지 확인하고 변환 로그의 원인을 기준으로 다시 시도하세요.",
73
+ "HWP_TEXT_EXTRACT_FAILED": "HWP 파일을 다른 뷰어에서 열어 유효성을 확인한 뒤 텍스트 추출을 다시 실행하세요.",
74
+ "IDEMPOTENT_REPLAY": "이미 적용된 planId입니다. 최신 preview/plan을 새로 만든 뒤 apply를 다시 호출하세요.",
75
+ "MEMO_NOT_FOUND": "list_memos 또는 문서 리소스에서 memoId를 다시 확인한 뒤 호출하세요.",
76
+ "MISSING_NODE": "대상 섹션, 문단, 표, 셀이 아직 존재하는지 조회한 뒤 새 앵커로 다시 실행하세요.",
77
+ "PARAGRAPH_INDEX_OUT_OF_RANGE": "list_paragraphs 결과의 paragraphIndex 범위 안에서 다시 선택하세요.",
78
+ "PERMISSION_DENIED": "허용된 workspace root와 파일 권한을 확인하고 쓰기 가능한 위치를 사용하세요.",
79
+ "PIPELINE_ERROR": "details.pipelineCode와 hint를 확인한 뒤 preview부터 다시 생성하세요.",
80
+ "PLAN_RECORD_MISSING": "preview_edit 또는 plan_edit으로 planId를 새로 발급받은 뒤 apply를 다시 호출하세요.",
81
+ "PREVIEW_REQUIRED": "preview_edit으로 변경 내용을 확인한 뒤 반환된 planId로 apply_edit을 호출하세요.",
82
+ "READ_ONLY_HWP_DOCUMENT": "HWP 바이너리는 직접 저장할 수 없습니다. 먼저 HWPX로 변환한 뒤 편집하세요.",
83
+ "RENDER_PREVIEW_INVALID_MODE": "mode는 'pages' 또는 'long'으로 지정한 뒤 다시 실행하세요.",
84
+ "RENDER_PREVIEW_INVALID_SCREENSHOT_MODE": "screenshot은 'auto', 'require', 'off' 중 하나로 지정하세요.",
85
+ "RENDER_PREVIEW_UNAVAILABLE": "matching python-hwpx 버전을 설치하고 MCP 서버를 새로 시작한 뒤 다시 실행하세요.",
86
+ "RANGE_OUT_OF_BOUNDS": "문단/문자 범위를 최신 문서 기준으로 다시 계산한 뒤 실행하세요.",
87
+ "REPAIR_UNAVAILABLE": "설치된 python-hwpx에 repair helper가 있는지 확인하고 플러그인을 다시 설치하세요.",
88
+ "SOURCE_FILE_TYPE_INVALID": "source에는 .hwp 파일을 전달하거나 HWPX 도구에는 .hwpx 경로를 사용하세요.",
89
+ "STYLE_BORDER_FILL_HEADER_MISSING": "문서 스타일 헤더가 손상되었습니다. repair_hwpx를 실행한 뒤 다시 시도하세요.",
90
+ "STYLE_CHAR_PROPERTY_ID_MISSING": "문서 문자 스타일 정의를 복구한 뒤 formatting 작업을 다시 실행하세요.",
91
+ "STYLE_HEADER_MISSING": "문서 style.xml/header 구성이 유효한지 확인하고 repair_hwpx를 먼저 실행하세요.",
92
+ "STYLE_ID_ALLOCATOR_MISSING": "문서 스타일 ID 할당 정보를 복구하거나 새 문서로 내용을 옮긴 뒤 다시 시도하세요.",
93
+ "TABLE_CELL_INDEX_OUT_OF_RANGE": "list_tables 결과로 행/열 범위를 확인한 뒤 유효한 셀 좌표를 사용하세요.",
94
+ "TABLE_CELL_OPERATION_FAILED": "병합 셀 구조와 행/열 좌표를 확인하고 단일 셀 대상으로 다시 실행하세요.",
95
+ "TABLE_EMPTY": "표에 행과 셀이 있는지 확인하고 비어 있으면 표를 다시 생성하세요.",
96
+ "TABLE_INDEX_OUT_OF_RANGE": "list_tables 결과의 tableIndex 범위 안에서 다시 선택하세요.",
97
+ "UNSAFE_WILDCARD": "와일드카드 범위를 줄이거나 정확한 문자열 매칭으로 preview를 다시 생성하세요.",
98
+ "WORKSPACE_OUTSIDE_ROOT": "mcp_server_health의 workspace.roots 안에 있는 경로를 사용하거나 호스트의 HWPX_AUTOMATION_WORKSPACE_ROOTS 설정을 갱신하세요(HWPX_MCP_WORKSPACE_ROOTS도 6.x에서 지원).",
99
+ "WORKSPACE_SYMLINK_ESCAPE": "작업공간 밖을 가리키는 심볼릭 링크를 제거하고 허용된 루트 안의 실제 경로를 사용하세요.",
100
+ "WORKSPACE_ROOT_INVALID": "기존 디렉터리를 HWPX_AUTOMATION_WORKSPACE_ROOTS JSON 배열로 지정한 뒤 호스트를 다시 시작하세요(HWPX_MCP_WORKSPACE_ROOTS도 6.x에서 지원).",
101
+ "WORKSPACE_PATH_INVALID": "비어 있지 않은 파일 경로를 지정하고 출력에는 디렉터리가 아닌 파일명을 사용하세요.",
102
+ "INVALID_ARGUMENT": "도구 스키마에 맞는 인자 형식과 값을 확인한 뒤 다시 호출하세요.",
103
+ "NETWORK_DESTINATION_DENIED": "기본 정책은 사설·루프백·링크로컬·예약 주소를 차단합니다. 신뢰된 사설 서비스가 꼭 필요할 때만 명시적 private-network opt-in을 사용하세요.",
104
+ "TOOL_EXECUTION_FAILED": "같은 입력을 반복하기 전에 오류 범주와 서버 상태를 확인하세요. 재현되면 민감정보를 제거한 최소 사례로 보고하세요.",
105
+ }
106
+
107
+
108
+ def category_for_error(error_code: str) -> ErrorCategory:
109
+ if error_code in {
110
+ "WORKSPACE_OUTSIDE_ROOT",
111
+ "WORKSPACE_SYMLINK_ESCAPE",
112
+ "WORKSPACE_ROOT_INVALID",
113
+ "PERMISSION_DENIED",
114
+ }:
115
+ return "permission"
116
+ if error_code in {"DOCUMENT_NOT_FOUND", "PLAN_RECORD_MISSING", "MEMO_NOT_FOUND"}:
117
+ return "not_found"
118
+ if error_code in {"CAPABILITY_SKEW", "REPAIR_UNAVAILABLE", "BYTE_PATCH_UNAVAILABLE"}:
119
+ return "capability"
120
+ if error_code.startswith("NETWORK_"):
121
+ return "network"
122
+ if error_code in {
123
+ "INVALID_ARGUMENT",
124
+ "WORKSPACE_PATH_INVALID",
125
+ "DOCUMENT_LOCATOR_REQUIRED",
126
+ "RANGE_OUT_OF_BOUNDS",
127
+ "TABLE_INDEX_OUT_OF_RANGE",
128
+ "PARAGRAPH_INDEX_OUT_OF_RANGE",
129
+ }:
130
+ return "validation"
131
+ if error_code in {"TOOL_EXECUTION_FAILED", "INTERNAL_ERROR"}:
132
+ return "internal"
133
+ return "document"
134
+
135
+
136
+ def mcp_code_for_error(error_code: str) -> int:
137
+ return ERROR_CODE_TO_MCP_CODE.get(error_code, DEFAULT_MCP_ERROR_CODE)
138
+
139
+
140
+ def suggestion_for_error(
141
+ error_code: str,
142
+ *,
143
+ details: Optional[Dict[str, Any]] = None,
144
+ hint: Optional[str] = None,
145
+ ) -> Optional[str]:
146
+ if error_code == "PIPELINE_ERROR" and details:
147
+ pipeline_code = details.get("pipelineCode")
148
+ if isinstance(pipeline_code, str):
149
+ mapped = DEFAULT_ERROR_SUGGESTIONS.get(pipeline_code)
150
+ if mapped:
151
+ return mapped
152
+ return DEFAULT_ERROR_SUGGESTIONS.get(error_code) or hint
153
+
154
+
155
+ def build_error_payload(
156
+ *,
157
+ code: str,
158
+ message: str,
159
+ details: Optional[Dict[str, Any]] = None,
160
+ hint: Optional[str] = None,
161
+ suggestion: Optional[str] = None,
162
+ category: Optional[ErrorCategory] = None,
163
+ retryable: bool = False,
164
+ ) -> Dict[str, Any]:
165
+ return CommonErrorModel(
166
+ code=code,
167
+ category=category or category_for_error(code),
168
+ message=message,
169
+ retryable=retryable,
170
+ details=details,
171
+ hint=hint,
172
+ suggestion=suggestion
173
+ or suggestion_for_error(code, details=details, hint=hint),
174
+ ).model_dump(exclude_none=True, by_alias=True)
@@ -0,0 +1,15 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Process-wide serialization for public document mutations."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import threading
7
+
8
+
9
+ # FastMCP can execute independent tool calls concurrently. Every catalog entry
10
+ # marked ``mutates`` shares this re-entrant lock so a verifier/rollback window
11
+ # cannot race another public writer in the same server process.
12
+ PUBLIC_MUTATION_LOCK = threading.RLock()
13
+
14
+
15
+ __all__ = ["PUBLIC_MUTATION_LOCK"]