revit-api-docs 0.2.0__tar.gz → 0.3.0__tar.gz

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 (72) hide show
  1. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/CHANGELOG.md +112 -1
  2. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/PKG-INFO +64 -29
  3. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/README.md +62 -27
  4. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/api_parser/parse_chm.py +23 -12
  5. revit_api_docs-0.3.0/pipeline/build_data_v1_1.py +992 -0
  6. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/embedder/embed.py +64 -27
  7. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pyproject.toml +2 -2
  8. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/__init__.py +1 -1
  9. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/config.py +2 -1
  10. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/data.py +14 -6
  11. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/default_config.yaml +4 -2
  12. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/reranker.py +57 -20
  13. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/retriever.py +475 -112
  14. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/server.py +33 -7
  15. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/conftest.py +63 -3
  16. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_bm25_index.py +12 -10
  17. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_data.py +2 -2
  18. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_rerank.py +90 -4
  19. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_retriever.py +33 -25
  20. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_server.py +37 -0
  21. revit_api_docs-0.3.0/tests/test_shipped_db.py +160 -0
  22. revit_api_docs-0.3.0/tests/test_vector_search.py +364 -0
  23. revit_api_docs-0.2.0/tests/test_shipped_db.py +0 -82
  24. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/.gitignore +0 -0
  25. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/LICENSE +0 -0
  26. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/__init__.py +0 -0
  27. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/api_parser/__init__.py +0 -0
  28. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/api_parser/quality_agent.py +0 -0
  29. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/demo_dual_store.py +0 -0
  30. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/demo_production_real.py +0 -0
  31. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/demo_real_golden.py +0 -0
  32. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/demo_real_scoring.py +0 -0
  33. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/demo_scoring.py +0 -0
  34. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/demo_sdk_cleaning.py +0 -0
  35. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/embedder/__init__.py +0 -0
  36. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/knowledge_builder/__init__.py +0 -0
  37. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/run_all.ipynb +0 -0
  38. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/sdk_parser/__init__.py +0 -0
  39. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/sdk_parser/extract.py +0 -0
  40. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/pipeline/sdk_parser/quality_agent.py +0 -0
  41. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/__main__.py +0 -0
  42. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/bm25.py +0 -0
  43. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/embedder/__init__.py +0 -0
  44. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/embedder/providers/__init__.py +0 -0
  45. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/embedder/providers/base.py +0 -0
  46. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/embedder/providers/google.py +0 -0
  47. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/embedder/providers/openai.py +0 -0
  48. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/environment.py +0 -0
  49. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/environment.yaml +0 -0
  50. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/llm_client.py +0 -0
  51. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/__init__.py +0 -0
  52. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/loader.py +0 -0
  53. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.api_quality_stage1_no_html.md +0 -0
  54. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.api_quality_stage1_system.md +0 -0
  55. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.api_quality_stage1_with_html.md +0 -0
  56. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.api_quality_stage2.md +0 -0
  57. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.api_quality_stage2_system.md +0 -0
  58. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.rewrite_query.md +0 -0
  59. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.rewrite_query_system.md +0 -0
  60. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_extract_readme_system.md +0 -0
  61. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_extract_readme_user.md +0 -0
  62. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_golden_code.md +0 -0
  63. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_golden_code_system.md +0 -0
  64. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_quality_file_batch.md +0 -0
  65. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_quality_file_system.md +0 -0
  66. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_quality_project.md +0 -0
  67. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/revit_api_docs/prompts/pipeline.sdk_quality_project_system.md +0 -0
  68. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/fixtures/retrieval_queries.yaml +0 -0
  69. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/fixtures/retrieval_queries_v2.yaml +0 -0
  70. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_bm25_recall.py +0 -0
  71. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_environment.py +0 -0
  72. {revit_api_docs-0.2.0 → revit_api_docs-0.3.0}/tests/test_package.py +0 -0
@@ -6,6 +6,116 @@ All notable changes to this project are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.0] - 2026-10-26
10
+
11
+ Vector hits now come back as the entries they describe and count also
12
+ without a reranker; reranking picks its provider from the keys that are set.
13
+ The data set `v1.1-data` adds constructor and interface member pages, and its
14
+ vector store lines up with the SQLite rows.
15
+
16
+ **Upgrading from 0.2.0** (`uvx --refresh revit-api-docs`): on the first start the server replaces an installed
17
+ `v1.0-data` (its `manifest.json` names the old release) with `v1.1-data`, a
18
+ download of 267 MB (all four files); a data directory without a
19
+ manifest (a hand-copied tree) is used as it is. With an embedding key and a
20
+ tree that still holds `v1.0-data`, the first vector query logs the warning
21
+ `vector_store_misaligned`: its record ids do not line up with the SQLite rows,
22
+ and hits are matched by entry name. Without any key nothing changes beyond the
23
+ new entries. Reranker choice: with only `COHERE_API_KEY` set Cohere still
24
+ reranks; with `TYPESAFE_API_KEY` set Jev now reranks without
25
+ `REVIT_API_DOCS_RERANK_PROVIDER=jev` (set the provider to `cohere` to keep
26
+ Cohere).
27
+
28
+ ### Added
29
+
30
+ - Data set `v1.1-data` (`RELEASE_TAG`; the download URL and SHA-256 list in
31
+ `data.py` follow it): the 27,596 entries of `v1.0-data` are kept unchanged
32
+ under the same ids, and 1,266 pages of the same reference are appended
33
+ (ids 27,597-28,862): 1,040 constructor pages (`XYZ(Double, Double, Double)
34
+ Constructor`, `Transaction(Document, String) Constructor`, overload lists)
35
+ and 226 members whose C# signature has no `public`, mostly interface
36
+ members (`IExternalEventHandler.Execute`, `IConnector.Origin`,
37
+ `IFailuresPreprocessor.PreprocessFailures`) and explicit interface
38
+ implementations. 28,862 entries in all. Source: `RevitAPI.chm` of the
39
+ Revit 2026.3 SDK, whose pages are the same set as the Revit 2026 reference
40
+ the first release was built from. The API vector store is rebuilt from the
41
+ new SQLite with the same model (`text-embedding-3-large`, 3072 dimensions):
42
+ one record per row and every record id is its row id, so the first vector
43
+ query no longer logs `vector_store_misaligned` (`download` reports
44
+ `aligned`). The SDK files (`revit_sdk.db`, `chromadb_code.tar.gz`) are the
45
+ `v1.0-data` ones.
46
+ - The vector documents are now `name : summary` (`v1.0-data` embedded mostly
47
+ the entry name alone: 21,952 of its 28,863 records); on the 223 test
48
+ queries this raised fused nDCG@5 without a reranker from 0.610 to 0.647
49
+ (task requests 0.438 to 0.459) and left it with Jev at 0.842 against 0.846
50
+ (task requests 0.778 against 0.794).
51
+ - `pipeline/build_data_v1_1.py` (sdist only): builds `v1.1-data` from the
52
+ `v1.0-data` SQLite and the CHM pages: appends the pages the base lacks
53
+ (pages whose name is in the base under another `full_id`, or whose content
54
+ is a base row's under a name the v1.0 rewrite changed, are listed and not
55
+ appended), runs the quality agent on the new rows only, re-embeds every
56
+ row, packages the four release files with `SHA256SUMS.txt` and checks the
57
+ vector store against the rows without an API call.
58
+
59
+ ### Fixed
60
+
61
+ - Vector search returned unrelated entries. The vector store of the
62
+ `v1.0-data` release numbers its 28,863 API records independently of the
63
+ 27,596 rows of `revit_api.db` (2 ids name the same entry in both), and hits
64
+ were looked up by record id. A hit is now matched to the row whose entry
65
+ name equals the record's `name` metadata (the row with the record's own id
66
+ when it carries that name; among rows sharing a name the one with the
67
+ record's `full_id` or `info`, else the lowest id). 27,591 records (95.6%)
68
+ reach 27,512 rows (99.7%); records without a row are dropped. The SDK sample
69
+ store's ids match its rows, and matching by project name keeps them. The
70
+ name map is built on the first vector query and kept in memory.
71
+ - Consistency probe: on the first vector query 50 records of each vector
72
+ collection are compared with SQLite. When fewer than 90% of the sampled ids
73
+ name the same entry as the row with that id, the warning
74
+ `vector_store_misaligned` is logged and hits are matched by name (`v1.0-data`:
75
+ 0/50 ids, 49/50 names). When fewer than 50% of the sampled names are found
76
+ either, vector search is off for the process and keyword search answers
77
+ alone. `revit-api-docs download` prints the check for the installed data set.
78
+ - A second retriever in the same process could not open the vector store
79
+ ("An instance of Chroma already exists ... with different settings"): each
80
+ ChromaDB client now gets its own `Settings` object.
81
+
82
+ ### Changed
83
+
84
+ - Hybrid ranking by reciprocal rank fusion: the vector hits and the BM25 hits,
85
+ `retrieval.api.top_k` (30) of each, are fused with score = sum of
86
+ 1 / (60 + rank), and the best 30 go to the reranker; without a reranker they
87
+ are cut to `top_k`. On equal scores a keyword hit comes first. Before, the
88
+ two lists were merged by distances on different scales, so without a
89
+ reranker vector-only hits never reached the top 5, and up to 60 candidates
90
+ went to the reranker. Without an embedding key the BM25 order and results
91
+ are unchanged. On 223 English test queries without reranking (measured on
92
+ `v1.1-data`): nDCG@5 0.557 with BM25 alone, 0.647 fused, and 0.355 -> 0.459
93
+ on the 113 multi-step task requests, whose answer is among the top 30 for
94
+ 82% instead of 72% of them.
95
+ - The default rerank provider is `auto`: Jev when `TYPESAFE_API_KEY` is set,
96
+ otherwise Cohere when `COHERE_API_KEY` is set, otherwise none.
97
+ `REVIT_API_DOCS_RERANK_PROVIDER` (now `auto`, `jev`, `cohere` or `none`)
98
+ still wins, and the `Rerank:` line names the provider that ran. README:
99
+ Jev is the recommended reranker, Cohere optional and the fallback for Jev.
100
+ - Cohere requests time out after 20 s instead of 10 s (the same as Jev); 10 s
101
+ cut off about 1% of calls.
102
+ - `search_revit_api` and `get_code_examples` are unchanged: names,
103
+ parameters and the first output line. The tool description now counts
104
+ 28,862 entries.
105
+ - CHM parser (`pipeline/api_parser/parse_chm.py`): `parse_single_html` and
106
+ `parse_all_api_html` take `keep_constructors` (default `False`, the old
107
+ behaviour); the C# signature no longer has to contain `public` (interface
108
+ members such as `void Execute(UIApplication app)` were skipped as a whole
109
+ page); a page with neither a signature nor a members table is still
110
+ skipped.
111
+ - `pipeline.embedder.embed.embed_api_data(..., resume=False,
112
+ document_template="NS")`: with `resume=True` the collection is kept and
113
+ only missing row ids are embedded; `document_template` picks the embedded
114
+ text per API row (`NS` `name : summary`, the default and the `v1.1-data`
115
+ store; `FS` `full_id : summary`, the earlier behaviour; `N` the entry name)
116
+ and is recorded in `meta.json`. `pipeline/build_data_v1_1.py
117
+ --document-template` passes it on (default `NS`).
118
+
9
119
  ## [0.2.0] - 2026-10-26
10
120
 
11
121
  Better candidates without any key, and an opt-in relevance check: BM25 keyword
@@ -147,6 +257,7 @@ no git history).
147
257
  - CI (tests + build on Linux/Windows, Python 3.11/3.13) and PyPI Trusted
148
258
  Publishing on version tags.
149
259
 
150
- [Unreleased]: https://github.com/revitbridge/revit-api-docs/compare/v0.2.0...HEAD
260
+ [Unreleased]: https://github.com/revitbridge/revit-api-docs/compare/v0.3.0...HEAD
261
+ [0.3.0]: https://github.com/revitbridge/revit-api-docs/compare/v0.2.0...v0.3.0
151
262
  [0.2.0]: https://github.com/revitbridge/revit-api-docs/compare/v0.1.0...v0.2.0
152
263
  [0.1.0]: https://github.com/revitbridge/revit-api-docs/releases/tag/v0.1.0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: revit-api-docs
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Revit API reference search for MCP hosts: local semantic + keyword lookup over the Revit 2026 API docs and SDK samples
5
5
  Project-URL: Homepage, https://github.com/revitbridge/revit-api-docs
6
6
  Project-URL: Issues, https://github.com/revitbridge/revit-api-docs/issues
7
7
  Project-URL: Changelog, https://github.com/revitbridge/revit-api-docs/blob/main/CHANGELOG.md
8
- Project-URL: Data, https://github.com/revitbridge/revit-api-docs/releases/tag/v1.0-data
8
+ Project-URL: Data, https://github.com/revitbridge/revit-api-docs/releases/tag/v1.1-data
9
9
  Author: revitbridge
10
10
  License-Expression: MIT
11
11
  License-File: LICENSE
@@ -35,8 +35,8 @@ Description-Content-Type: text/markdown
35
35
  # revit-api-docs
36
36
 
37
37
  Revit API reference search as an MCP server: two read-only tools over a local
38
- copy of the Revit 2026 API documentation (27,596 classes, methods, properties
39
- and enums) and the official SDK samples (153 projects).
38
+ copy of the Revit 2026 API documentation (28,862 classes, constructors,
39
+ methods, properties and enums) and the official SDK samples (153 projects).
40
40
 
41
41
  **Optional.** It exists for models that do not know the Revit API well. If
42
42
  your model already writes correct Revit code, you do not need it;
@@ -97,8 +97,8 @@ keep it on a loopback address, or put it behind a reverse proxy that
97
97
  authenticates; the server logs a warning when `--host` is not a loopback
98
98
  address.
99
99
 
100
- On the first start the server downloads the data set (335 MB, four files) from
101
- this repository's [`v1.0-data` release](https://github.com/revitbridge/revit-api-docs/releases/tag/v1.0-data)
100
+ On the first start the server downloads the data set (267 MB, four files) from
101
+ this repository's [`v1.1-data` release](https://github.com/revitbridge/revit-api-docs/releases/tag/v1.1-data)
102
102
  into `%LOCALAPPDATA%\revit-api-docs` (Windows) or `~/.local/share/revit-api-docs`
103
103
  (Linux; `~/Library/Application Support/revit-api-docs` on macOS), verifies each
104
104
  file's SHA-256 and unpacks the vector stores. Tool calls made while that runs
@@ -133,11 +133,13 @@ reference: BM25 over a full-text index of entry names, IDs, summaries and
133
133
  signatures, where identifiers also match by their camel-case parts, so a
134
134
  misspelt or unknown name still gets candidates. The index (11.8 MB) is built
135
135
  next to the data set on first use (under a second). With an embedding key it
136
- adds semantic search over the vector store, and with a Cohere key it reranks
137
- the merged candidates; with a TypeSafe key it can rerank with Jev instead, which
138
- returns a calibrated relevance per entry. With a threshold set and no entry
139
- reaching it, the output starts with an abstention line and then lists the
140
- candidates with their relevance, for reference. See Configure.
136
+ adds semantic search over the vector store and fuses the two rankings by rank,
137
+ which helps most with task descriptions that do not name the API. With a
138
+ TypeSafe key it reranks the candidates with Jev, which returns a calibrated
139
+ relevance per entry; with only a Cohere key it reranks with Cohere. With a Jev
140
+ threshold set and no entry reaching it, the output starts with an abstention
141
+ line and then lists the candidates with their relevance, for reference. See
142
+ Configure.
141
143
 
142
144
  Try it from a terminal (installs the data set if needed):
143
145
 
@@ -158,39 +160,72 @@ All settings are environment variables; there is no config file to edit.
158
160
  | `REVIT_API_DOCS_EMBEDDING_API_KEY` | *(unset)* | Key for the embedding endpoint; turns on semantic (vector) search. `OPENROUTER_API_KEY` is used when this is unset |
159
161
  | `REVIT_API_DOCS_EMBEDDING_BASE_URL` | `https://openrouter.ai/api/v1` | Any OpenAI-compatible `/embeddings` endpoint |
160
162
  | `REVIT_API_DOCS_EMBEDDING_MODEL` | `openai/text-embedding-3-large` | Must produce the same 3072-dimensional space the shipped vectors were built with (`text-embedding-3-large`); another model makes vector search return noise |
161
- | `COHERE_API_KEY` | *(unset)* | Enables reranking with Cohere `rerank-v3.5` (native REST API) |
162
- | `REVIT_API_DOCS_RERANK_PROVIDER` | `cohere` | `cohere`, `jev` or `none`. With `jev`, a failed or unconfigured Jev call falls back to Cohere when `COHERE_API_KEY` is set, otherwise to no reranking; the first output line says which one ran |
163
- | `TYPESAFE_API_KEY` | *(unset)* | Key for TypeSafe System One (Jev), used when the provider is `jev`. At most 30 candidates per request, 2 requests in flight, 2 retries, 20 s timeout |
163
+ | `TYPESAFE_API_KEY` | *(unset)* | Key for TypeSafe System One (Jev), the recommended reranker: with the default provider `auto` setting this key is enough. At most 30 candidates per request, 2 requests in flight, 2 retries, 20 s timeout |
164
+ | `COHERE_API_KEY` | *(unset)* | Optional. Cohere `rerank-v3.5` (native REST API, 20 s timeout): reranks when it is the only rerank key set, and is the fallback for a failed Jev call when both are set |
165
+ | `REVIT_API_DOCS_RERANK_PROVIDER` | `auto` | `auto`, `jev`, `cohere` or `none`. `auto` reranks with Jev when `TYPESAFE_API_KEY` is set, otherwise with Cohere when `COHERE_API_KEY` is set, otherwise not at all; an explicit value wins. With Jev, a failed or unconfigured call falls back to Cohere when `COHERE_API_KEY` is set, otherwise to no reranking; the first output line says which one ran |
164
166
  | `REVIT_API_DOCS_JEV_MODEL` | `jev-latest` | Jev model or alias; pin a version such as `jev-1.14.0` for reproducible results |
165
167
  | `REVIT_API_DOCS_MIN_RELEVANCE` | *(unset)* | Probability 0-1 (`retrieval.api.min_relevance`). Only honoured while Jev ranks the results, and it only decides whether to abstain: no entry is dropped, every result keeps its `Relevance` line. When no entry reaches it, `search_revit_api` starts with "No entry in the Revit 2026 data set scored high enough for this query", notes that the member may be absent from this version or listed under a different name or wording, and lists the low-scoring candidates for reference. No effect with Cohere or without reranking. See "Reranking with Jev" below |
166
- | `REVIT_API_DOCS_RELEASE_URL` | this repository's `v1.0-data` release | Mirror for the data files; the SHA-256 checks still apply |
168
+ | `REVIT_API_DOCS_RELEASE_URL` | this repository's `v1.1-data` release | Mirror for the data files; the SHA-256 checks still apply |
167
169
  | `HTTPS_PROXY` / `HTTP_PROXY` | *(unset)* | Proxy for the embedding and rerank calls |
168
170
 
169
171
  Pass them through the `env` block of your MCP host's server entry.
170
172
 
171
- **Reranking with Jev.** If you have a `TYPESAFE_API_KEY`,
172
- `REVIT_API_DOCS_RERANK_PROVIDER=jev` is the recommended setting (the default
173
- provider stays `cohere`). On 60 English test queries (50 with a known answer)
174
- over the keyword (BM25) candidates, with no embedding key, Jev raised nDCG@5
175
- from 0.675 to 0.871 and never turned a correct top-5 answer into a miss.
176
- Input tokens cost about $0.23 per 1,000 queries.
173
+ Recommended setup: a `TYPESAFE_API_KEY` (Jev reranking), plus an embedding key
174
+ when requests describe multi-step tasks rather than name APIs. Without any key
175
+ the server runs on BM25 keyword search alone.
176
+
177
+ **Reranking with Jev.** Jev is the recommended reranker, and the default
178
+ provider (`auto`) uses it whenever `TYPESAFE_API_KEY` is set. Cohere is
179
+ optional: `auto` uses it when only `COHERE_API_KEY` is set, and with both keys
180
+ it is the fallback for a failed Jev call. Measured on `v1.0-data`: on 60
181
+ English test queries (50 with a known answer) over the keyword (BM25)
182
+ candidates, with no embedding key, Jev raised nDCG@5 from 0.675 to 0.871 and
183
+ never turned a correct top-5 answer into a miss. On 223 further queries over
184
+ the same candidates Jev reached an nDCG@5 of 0.788 against Cohere's 0.674. Input tokens cost about $0.23 per 1,000
185
+ queries; Cohere bills $2 per 1,000 searches.
177
186
  `REVIT_API_DOCS_MIN_RELEVANCE` stays unset by default. Set to 0.15 it filters
178
187
  out clearly unrelated queries (questions that are not about Revit, types this
179
188
  data set does not have), abstaining on about 2.5% of the queries that do have
180
- an answer. It cannot spot a misspelt or misplaced member name: such a query
181
- usually gets the closest real API as the first result, to be confirmed with a
182
- compile check. **Do not use 0.5**: it abstained on 14% of the queries that
183
- have an answer. What TypeSafe keeps: see the `jev-data-handling` note
189
+ an answer (measured on `v1.0-data`). It cannot spot a misspelt or misplaced
190
+ member name: such a query usually gets the closest real API as the first
191
+ result, to be confirmed with a compile check. **Do not use 0.5**: it
192
+ abstained on 14% of the queries that have an answer. What TypeSafe keeps: see the `jev-data-handling` note
184
193
  (`uvx revit-api-docs environment typesafe`).
185
194
 
195
+ **Vector search.** An embedding key (`REVIT_API_DOCS_EMBEDDING_API_KEY`, or
196
+ `OPENROUTER_API_KEY`) turns it on; each query then costs one embedding request
197
+ (about 0.9 s). The vector hits and the BM25 hits, 30 of each, are fused by
198
+ reciprocal rank (score = sum of 1 / (60 + rank)) and the best 30 go to the
199
+ reranker; without a reranker they are cut to `top_k`. On 223 English test
200
+ queries without reranking (measured on `v1.1-data`), fusion raises nDCG@5
201
+ from 0.557 (BM25 alone) to 0.647, and on the 113 of them that describe a
202
+ multi-step task from 0.355 to 0.459, with an answer among the top 30 for 82%
203
+ of those instead of 72%. Each
204
+ vector hit is matched to its entry by name. On the first vector query the
205
+ server samples 50 records of each vector collection: when the record ids do
206
+ not line up with the rows it logs the warning `vector_store_misaligned` and
207
+ keeps matching by name (the older `v1.0-data` vector store numbers its records
208
+ differently from the rows of `revit_api.db`; `v1.1-data` is aligned and logs
209
+ nothing); when the names are not found either, it turns vector search off
210
+ until the server restarts and answers from keyword search. `revit-api-docs download`
211
+ prints the same check for the installed data set.
212
+
186
213
  Privacy: with an embedding, Cohere or TypeSafe key the query text and the
187
214
  candidate API entries (public documentation) are sent to that provider. Keep
188
215
  queries to API names and generic task descriptions, in English.
189
216
 
190
- Data set: the SQLite databases and ChromaDB indexes were built from the Revit
191
- 2026 API CHM and the Revit 2026 SDK samples with the pipeline in `pipeline/`
192
- (`uv sync --extra pipeline`; needs the CHM, the SDK and OpenRouter/Cohere keys
193
- in the environment). The server does not need any of that.
217
+ Data set (`v1.1-data`): the API reference comes from `RevitAPI.chm` of the
218
+ Revit 2026.3 SDK (the same pages as the Revit 2026 reference) and includes
219
+ constructor pages and interface members such as
220
+ `IExternalEventHandler.Execute`: 28,862 entries, of which the 27,596 of
221
+ `v1.0-data` are unchanged under the same ids. The SDK samples (153 projects)
222
+ come from the Revit 2026 SDK. The SQLite databases and ChromaDB indexes were
223
+ built with the pipeline in `pipeline/` (`uv sync --extra pipeline`; needs the
224
+ CHM, the SDK and OpenRouter/Cohere keys in the environment). `v1.1-data` was
225
+ built from `v1.0-data` with `uv run python -m pipeline.build_data_v1_1
226
+ --html-dir <CHM html dir> --base-db <v1.0-data dir>/sqlite/revit_api.db`, which
227
+ appends the pages `v1.0-data` lacked and rebuilds the API vector store so that
228
+ every record id is its row id. The server does not need any of that.
194
229
 
195
230
  Development:
196
231
 
@@ -1,8 +1,8 @@
1
1
  # revit-api-docs
2
2
 
3
3
  Revit API reference search as an MCP server: two read-only tools over a local
4
- copy of the Revit 2026 API documentation (27,596 classes, methods, properties
5
- and enums) and the official SDK samples (153 projects).
4
+ copy of the Revit 2026 API documentation (28,862 classes, constructors,
5
+ methods, properties and enums) and the official SDK samples (153 projects).
6
6
 
7
7
  **Optional.** It exists for models that do not know the Revit API well. If
8
8
  your model already writes correct Revit code, you do not need it;
@@ -63,8 +63,8 @@ keep it on a loopback address, or put it behind a reverse proxy that
63
63
  authenticates; the server logs a warning when `--host` is not a loopback
64
64
  address.
65
65
 
66
- On the first start the server downloads the data set (335 MB, four files) from
67
- this repository's [`v1.0-data` release](https://github.com/revitbridge/revit-api-docs/releases/tag/v1.0-data)
66
+ On the first start the server downloads the data set (267 MB, four files) from
67
+ this repository's [`v1.1-data` release](https://github.com/revitbridge/revit-api-docs/releases/tag/v1.1-data)
68
68
  into `%LOCALAPPDATA%\revit-api-docs` (Windows) or `~/.local/share/revit-api-docs`
69
69
  (Linux; `~/Library/Application Support/revit-api-docs` on macOS), verifies each
70
70
  file's SHA-256 and unpacks the vector stores. Tool calls made while that runs
@@ -99,11 +99,13 @@ reference: BM25 over a full-text index of entry names, IDs, summaries and
99
99
  signatures, where identifiers also match by their camel-case parts, so a
100
100
  misspelt or unknown name still gets candidates. The index (11.8 MB) is built
101
101
  next to the data set on first use (under a second). With an embedding key it
102
- adds semantic search over the vector store, and with a Cohere key it reranks
103
- the merged candidates; with a TypeSafe key it can rerank with Jev instead, which
104
- returns a calibrated relevance per entry. With a threshold set and no entry
105
- reaching it, the output starts with an abstention line and then lists the
106
- candidates with their relevance, for reference. See Configure.
102
+ adds semantic search over the vector store and fuses the two rankings by rank,
103
+ which helps most with task descriptions that do not name the API. With a
104
+ TypeSafe key it reranks the candidates with Jev, which returns a calibrated
105
+ relevance per entry; with only a Cohere key it reranks with Cohere. With a Jev
106
+ threshold set and no entry reaching it, the output starts with an abstention
107
+ line and then lists the candidates with their relevance, for reference. See
108
+ Configure.
107
109
 
108
110
  Try it from a terminal (installs the data set if needed):
109
111
 
@@ -124,39 +126,72 @@ All settings are environment variables; there is no config file to edit.
124
126
  | `REVIT_API_DOCS_EMBEDDING_API_KEY` | *(unset)* | Key for the embedding endpoint; turns on semantic (vector) search. `OPENROUTER_API_KEY` is used when this is unset |
125
127
  | `REVIT_API_DOCS_EMBEDDING_BASE_URL` | `https://openrouter.ai/api/v1` | Any OpenAI-compatible `/embeddings` endpoint |
126
128
  | `REVIT_API_DOCS_EMBEDDING_MODEL` | `openai/text-embedding-3-large` | Must produce the same 3072-dimensional space the shipped vectors were built with (`text-embedding-3-large`); another model makes vector search return noise |
127
- | `COHERE_API_KEY` | *(unset)* | Enables reranking with Cohere `rerank-v3.5` (native REST API) |
128
- | `REVIT_API_DOCS_RERANK_PROVIDER` | `cohere` | `cohere`, `jev` or `none`. With `jev`, a failed or unconfigured Jev call falls back to Cohere when `COHERE_API_KEY` is set, otherwise to no reranking; the first output line says which one ran |
129
- | `TYPESAFE_API_KEY` | *(unset)* | Key for TypeSafe System One (Jev), used when the provider is `jev`. At most 30 candidates per request, 2 requests in flight, 2 retries, 20 s timeout |
129
+ | `TYPESAFE_API_KEY` | *(unset)* | Key for TypeSafe System One (Jev), the recommended reranker: with the default provider `auto` setting this key is enough. At most 30 candidates per request, 2 requests in flight, 2 retries, 20 s timeout |
130
+ | `COHERE_API_KEY` | *(unset)* | Optional. Cohere `rerank-v3.5` (native REST API, 20 s timeout): reranks when it is the only rerank key set, and is the fallback for a failed Jev call when both are set |
131
+ | `REVIT_API_DOCS_RERANK_PROVIDER` | `auto` | `auto`, `jev`, `cohere` or `none`. `auto` reranks with Jev when `TYPESAFE_API_KEY` is set, otherwise with Cohere when `COHERE_API_KEY` is set, otherwise not at all; an explicit value wins. With Jev, a failed or unconfigured call falls back to Cohere when `COHERE_API_KEY` is set, otherwise to no reranking; the first output line says which one ran |
130
132
  | `REVIT_API_DOCS_JEV_MODEL` | `jev-latest` | Jev model or alias; pin a version such as `jev-1.14.0` for reproducible results |
131
133
  | `REVIT_API_DOCS_MIN_RELEVANCE` | *(unset)* | Probability 0-1 (`retrieval.api.min_relevance`). Only honoured while Jev ranks the results, and it only decides whether to abstain: no entry is dropped, every result keeps its `Relevance` line. When no entry reaches it, `search_revit_api` starts with "No entry in the Revit 2026 data set scored high enough for this query", notes that the member may be absent from this version or listed under a different name or wording, and lists the low-scoring candidates for reference. No effect with Cohere or without reranking. See "Reranking with Jev" below |
132
- | `REVIT_API_DOCS_RELEASE_URL` | this repository's `v1.0-data` release | Mirror for the data files; the SHA-256 checks still apply |
134
+ | `REVIT_API_DOCS_RELEASE_URL` | this repository's `v1.1-data` release | Mirror for the data files; the SHA-256 checks still apply |
133
135
  | `HTTPS_PROXY` / `HTTP_PROXY` | *(unset)* | Proxy for the embedding and rerank calls |
134
136
 
135
137
  Pass them through the `env` block of your MCP host's server entry.
136
138
 
137
- **Reranking with Jev.** If you have a `TYPESAFE_API_KEY`,
138
- `REVIT_API_DOCS_RERANK_PROVIDER=jev` is the recommended setting (the default
139
- provider stays `cohere`). On 60 English test queries (50 with a known answer)
140
- over the keyword (BM25) candidates, with no embedding key, Jev raised nDCG@5
141
- from 0.675 to 0.871 and never turned a correct top-5 answer into a miss.
142
- Input tokens cost about $0.23 per 1,000 queries.
139
+ Recommended setup: a `TYPESAFE_API_KEY` (Jev reranking), plus an embedding key
140
+ when requests describe multi-step tasks rather than name APIs. Without any key
141
+ the server runs on BM25 keyword search alone.
142
+
143
+ **Reranking with Jev.** Jev is the recommended reranker, and the default
144
+ provider (`auto`) uses it whenever `TYPESAFE_API_KEY` is set. Cohere is
145
+ optional: `auto` uses it when only `COHERE_API_KEY` is set, and with both keys
146
+ it is the fallback for a failed Jev call. Measured on `v1.0-data`: on 60
147
+ English test queries (50 with a known answer) over the keyword (BM25)
148
+ candidates, with no embedding key, Jev raised nDCG@5 from 0.675 to 0.871 and
149
+ never turned a correct top-5 answer into a miss. On 223 further queries over
150
+ the same candidates Jev reached an nDCG@5 of 0.788 against Cohere's 0.674. Input tokens cost about $0.23 per 1,000
151
+ queries; Cohere bills $2 per 1,000 searches.
143
152
  `REVIT_API_DOCS_MIN_RELEVANCE` stays unset by default. Set to 0.15 it filters
144
153
  out clearly unrelated queries (questions that are not about Revit, types this
145
154
  data set does not have), abstaining on about 2.5% of the queries that do have
146
- an answer. It cannot spot a misspelt or misplaced member name: such a query
147
- usually gets the closest real API as the first result, to be confirmed with a
148
- compile check. **Do not use 0.5**: it abstained on 14% of the queries that
149
- have an answer. What TypeSafe keeps: see the `jev-data-handling` note
155
+ an answer (measured on `v1.0-data`). It cannot spot a misspelt or misplaced
156
+ member name: such a query usually gets the closest real API as the first
157
+ result, to be confirmed with a compile check. **Do not use 0.5**: it
158
+ abstained on 14% of the queries that have an answer. What TypeSafe keeps: see the `jev-data-handling` note
150
159
  (`uvx revit-api-docs environment typesafe`).
151
160
 
161
+ **Vector search.** An embedding key (`REVIT_API_DOCS_EMBEDDING_API_KEY`, or
162
+ `OPENROUTER_API_KEY`) turns it on; each query then costs one embedding request
163
+ (about 0.9 s). The vector hits and the BM25 hits, 30 of each, are fused by
164
+ reciprocal rank (score = sum of 1 / (60 + rank)) and the best 30 go to the
165
+ reranker; without a reranker they are cut to `top_k`. On 223 English test
166
+ queries without reranking (measured on `v1.1-data`), fusion raises nDCG@5
167
+ from 0.557 (BM25 alone) to 0.647, and on the 113 of them that describe a
168
+ multi-step task from 0.355 to 0.459, with an answer among the top 30 for 82%
169
+ of those instead of 72%. Each
170
+ vector hit is matched to its entry by name. On the first vector query the
171
+ server samples 50 records of each vector collection: when the record ids do
172
+ not line up with the rows it logs the warning `vector_store_misaligned` and
173
+ keeps matching by name (the older `v1.0-data` vector store numbers its records
174
+ differently from the rows of `revit_api.db`; `v1.1-data` is aligned and logs
175
+ nothing); when the names are not found either, it turns vector search off
176
+ until the server restarts and answers from keyword search. `revit-api-docs download`
177
+ prints the same check for the installed data set.
178
+
152
179
  Privacy: with an embedding, Cohere or TypeSafe key the query text and the
153
180
  candidate API entries (public documentation) are sent to that provider. Keep
154
181
  queries to API names and generic task descriptions, in English.
155
182
 
156
- Data set: the SQLite databases and ChromaDB indexes were built from the Revit
157
- 2026 API CHM and the Revit 2026 SDK samples with the pipeline in `pipeline/`
158
- (`uv sync --extra pipeline`; needs the CHM, the SDK and OpenRouter/Cohere keys
159
- in the environment). The server does not need any of that.
183
+ Data set (`v1.1-data`): the API reference comes from `RevitAPI.chm` of the
184
+ Revit 2026.3 SDK (the same pages as the Revit 2026 reference) and includes
185
+ constructor pages and interface members such as
186
+ `IExternalEventHandler.Execute`: 28,862 entries, of which the 27,596 of
187
+ `v1.0-data` are unchanged under the same ids. The SDK samples (153 projects)
188
+ come from the Revit 2026 SDK. The SQLite databases and ChromaDB indexes were
189
+ built with the pipeline in `pipeline/` (`uv sync --extra pipeline`; needs the
190
+ CHM, the SDK and OpenRouter/Cohere keys in the environment). `v1.1-data` was
191
+ built from `v1.0-data` with `uv run python -m pipeline.build_data_v1_1
192
+ --html-dir <CHM html dir> --base-db <v1.0-data dir>/sqlite/revit_api.db`, which
193
+ appends the pages `v1.0-data` lacked and rebuilds the API vector store so that
194
+ every record id is its row id. The server does not need any of that.
160
195
 
161
196
  Development:
162
197
 
@@ -19,13 +19,19 @@ from pathlib import Path
19
19
  from bs4 import BeautifulSoup
20
20
 
21
21
 
22
- def parse_single_html(html_path: str) -> dict | None:
22
+ def parse_single_html(html_path: str, *, keep_constructors: bool = False) -> dict | None:
23
23
  """
24
24
  解析单个 API HTML 文件,提取结构化数据
25
25
 
26
+ Args:
27
+ html_path: HTML 文件路径
28
+ keep_constructors: True 时保留构造函数页(data release v1.1 起收录);
29
+ 默认 False,与旧行为相同(丢弃构造函数页)
30
+
26
31
  Returns:
27
32
  dict with keys: name, full_id, namespace, content_type, info, summary,
28
- remark, parameters, exceptions, members, keywords
33
+ remark, parameters, exceptions, members, keywords,
34
+ _source_file(源 HTML 路径,供 quality_agent 读取原文;不入 SQLite)
29
35
  如果不是有效的 API 文档页面返回 None
30
36
  """
31
37
  try:
@@ -52,8 +58,9 @@ def parse_single_html(html_path: str) -> dict | None:
52
58
  return None
53
59
 
54
60
  # --- 过滤构造函数页面(ctor) ---
55
- # 构造函数仅描述如何实例化对象,不含方法逻辑,对 RAG 检索意义有限
56
- if _is_constructor_page(title, full_id):
61
+ # 旧版默认丢弃构造函数页;keep_constructors=True 时保留(v1.1-data 起收录,
62
+ # `new XYZ(x, y, z)`、`new Transaction(doc, name)` 之类的查询需要它们)
63
+ if not keep_constructors and _is_constructor_page(title, full_id):
57
64
  return None
58
65
 
59
66
  # 命名空间
@@ -184,8 +191,10 @@ def _extract_api_fullname(soup: BeautifulSoup, title: str) -> str | None:
184
191
 
185
192
  def _extract_csharp_signature(soup: BeautifulSoup) -> str:
186
193
  """
187
- 从 HTML 中提取 C# 方法签名,仅保留包含 public 的签名。
188
- 对应旧版 get_csharp_full_name 逻辑。
194
+ 从 HTML 中提取 C# 签名(IDAB_code_Div1 的 <pre>,非空即可)。
195
+ 对应旧版 get_csharp_full_name 逻辑;旧版只保留含 public 的签名,接口成员
196
+ (如 `void Execute(UIApplication app)`)与显式接口实现因此被整页跳过,
197
+ 现在不再要求 public。
189
198
  """
190
199
  div = soup.find("div", id="IDAB_code_Div1")
191
200
  if not div:
@@ -196,7 +205,7 @@ def _extract_csharp_signature(soup: BeautifulSoup) -> str:
196
205
  return ""
197
206
 
198
207
  text = pre.get_text(separator=" ", strip=True)
199
- if "public" not in text:
208
+ if not text:
200
209
  return ""
201
210
 
202
211
  # 归一化空白
@@ -345,16 +354,18 @@ def _extract_members_table(topic_content) -> str:
345
354
  return "\n".join(members)
346
355
 
347
356
 
348
- def parse_all_api_html(html_dir: str, *, limit: int | None = None) -> list[dict]:
357
+ def parse_all_api_html(html_dir: str, *, limit: int | None = None,
358
+ keep_constructors: bool = False) -> list[dict]:
349
359
  """
350
360
  解析目录下所有(或前 limit 个)API HTML 文件
351
361
 
352
362
  Args:
353
- html_dir: CHM 解压后的 HTML 文件目录
354
- limit: 仅解析前 N 个文件(调试用),None 表示全量
363
+ html_dir: CHM 解压后的 HTML 文件目录
364
+ limit: 仅解析前 N 个文件(调试用),None 表示全量
365
+ keep_constructors: True 时保留构造函数页(见 parse_single_html)
355
366
 
356
367
  Returns:
357
- list of parsed API data dicts(已过滤构造函数、命名空间页等噪音)
368
+ list of parsed API data dicts(已过滤命名空间页等噪音;默认也过滤构造函数)
358
369
  """
359
370
  results = []
360
371
  html_dir = Path(html_dir)
@@ -372,7 +383,7 @@ def parse_all_api_html(html_dir: str, *, limit: int | None = None) -> list[dict]
372
383
  if i % 1000 == 0 and i > 0:
373
384
  print(f" 解析进度: {i}/{total} 有效={len(results)} ctor跳过={skipped_ctor} 噪音跳过={skipped_noise}")
374
385
  try:
375
- data = parse_single_html(str(html_file))
386
+ data = parse_single_html(str(html_file), keep_constructors=keep_constructors)
376
387
  if data:
377
388
  results.append(data)
378
389
  else: