feat(native): add rebuild-on-change for NativeModule#1599
Open
jeff-hykin wants to merge 23 commits intodevfrom
Open
feat(native): add rebuild-on-change for NativeModule#1599jeff-hykin wants to merge 23 commits intodevfrom
jeff-hykin wants to merge 23 commits intodevfrom
Conversation
Add a generic file change detection utility (dimos/utils/change_detect.py) that tracks content hashes via xxhash and integrate it into NativeModule so it can automatically rebuild when watched source files change. - change_detect.did_change() hashes file content, stores per-cache-name hash files in the venv, and returns True when files differ - NativeModuleConfig gains rebuild_on_change: list[str] | None - NativeModule._maybe_build() deletes stale executables when sources change - 11 tests for change_detect, 3 integration tests for native rebuild
…avoid unlinking Nix store executables - Add `cwd` parameter to `did_change()` and `_resolve_paths()` so relative glob patterns in `rebuild_on_change` are resolved against the module's working directory instead of the process cwd. - Replace `exe.unlink()` with a `needs_rebuild` flag so executables that live in read-only locations (e.g. Nix store) are not deleted; instead the build command is re-run which handles the output path itself.
…avoid unlinking Nix store executables - Add `cwd` parameter to `did_change()` and `_resolve_paths()` so relative glob patterns in `rebuild_on_change` are resolved against the module's working directory instead of the process cwd. - Replace `exe.unlink()` with a `needs_rebuild` flag so executables that live in read-only locations (e.g. Nix store) are not deleted; instead the build command is re-run which handles the output path itself. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
Greptile SummaryThis PR adds a content-hash-based file change detection utility ( Key changes and findings:
Confidence Score: 3/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[NativeModule._maybe_build] --> B{rebuild_on_change\nset AND exe exists?}
B -- No --> C{exe exists?}
B -- Yes --> D["did_change(cache_name, paths, cwd)\n⚠ writes hash to cache immediately"]
D -- False\nno change --> C
D -- True\nfiles changed --> E[needs_rebuild = True\nlog 'Source files changed']
C -- Yes and not needs_rebuild --> F[return early\nno build]
C -- No OR needs_rebuild --> G{build_command set?}
G -- No --> H[raise FileNotFoundError]
G -- Yes --> I[subprocess.Popen build_command]
I --> J{returncode == 0?}
J -- No --> K[raise RuntimeError\n⚠ cache already updated\nfuture rebuilds blocked]
J -- Yes --> L{exe exists\nafter build?}
L -- No --> M[raise FileNotFoundError]
L -- Yes --> N["did_change(cache_name, paths, cwd)\nseed cache post-build\n⚠ cwd arg present here"]
N --> O[build complete]
Reviews (2): Last reviewed commit: "fix(test): isolate LCM multicast in flak..." | Re-trigger Greptile |
bfab461 to
e01688c
Compare
…imos into jeff/feat/native_rebuild
fa3defd to
cb5041b
Compare
# Conflicts: # uv.lock
fcntl.flock is per-file-description, not per-thread. Two threads in the same process can both hold LOCK_EX simultaneously. Add a per-cache-name threading.Lock to protect intra-process concurrent access. Revert: git revert HEAD
Two NativeModule subclasses in the same file would share a cache key, corrupting each other's rebuild state. Add qualname to disambiguate. Revert: git revert HEAD
Move super().stop() before self._process = None so the asyncio loop thread is joined before tests see the exit signal. Wrap crash test in try/finally with mod.stop().
Use dedicated multicast addresses to prevent cross-test contamination in test_pattern_sub.py and test_lcmpubsub.py.
…imos into jeff/feat/native_rebuild # Conflicts: # dimos/core/native_module.py # dimos/utils/change_detect.py
- P0: did_change() no longer writes cache before build completes. Added update=False param to check without updating, and update_cache() to explicitly write after successful build. - P0: native_module uses update=False for pre-build check, update_cache() only after confirmed-good build. Failed builds won't poison the cache. - P1: xxhash already in pyproject.toml deps (resolved by dev merge). - P2: did_change update param gives callers control over when to persist. - P2: test_nonexistent_path_warns now asserts result is False (not just bool). - Added tests for update=False and update_cache workflows.
6 tasks
dimos/core/native_module.py
Outdated
| # Uses update_cache (not did_change) so we only write the hash after a | ||
| # confirmed-good build — a failed build won't poison the cache. | ||
| if self.config.rebuild_on_change: | ||
| from dimos.utils.change_detect import update_cache |
Contributor
There was a problem hiding this comment.
Move to the top. You already ahve this file imported.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Editing source code doesnt cause native modules to rebuild. Very easy to forget and not friendly for ai edits.
Solution
Some generic utils:
dimos/utils/change_detect.py: Content-hash-based file change detection usingxxhash.NativeModuleConfig.rebuild_on_change: Optionallist[str|Path|Glob]Breaking Changes
None
How to Test
Contributor License Agreement