feat(prompt): add hot-reloadable local customization - #90
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis release adds configurable, hot-reloaded local prompt file slots, modularizes prompt resources, updates prompt documentation and packaging exclusions, and extends text tool-call parsing for ChangesPrompt customization
Text tool-call compatibility
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant RuntimeConfig
participant PromptBuilder
participant PromptFileIncludes
participant LocalPromptFile
RuntimeConfig->>PromptBuilder: provide prompt_file_includes paths
PromptBuilder->>PromptFileIncludes: apply paths to system prompt markers
PromptFileIncludes->>LocalPromptFile: read configured slot files
LocalPromptFile-->>PromptFileIncludes: return file contents
PromptFileIncludes-->>PromptBuilder: return substituted system prompt
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
src/Undefined/ai/prompts/file_includes.py (2)
45-69: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winConsider mtime-based caching to avoid re-reading include files on every request.
apply_prompt_file_includesis invoked frombuild_messageson every AI request (perbuilder.pylines 306-320), and re-reads every configured include file each time to support hot reload. A small in-memory cache keyed by(path, mtime)would preserve the hot-reload guarantee (content changes bump mtime → cache miss → re-read) while eliminating redundant disk I/O for the common case where files are unchanged, which matters more under the project's high-concurrency design.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Undefined/ai/prompts/file_includes.py` around lines 45 - 69, Update apply_prompt_file_includes and its include-file loading path to cache loaded contents by the configured file path and current modification time. Reuse cached content when the mtime is unchanged, invalidate it and reread the file when the mtime changes, and preserve the existing hot-reload behavior and error handling.
52-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUnrecognized/invalid slot keys are silently dropped without a warning.
Slots not in
PROMPT_FILE_INCLUDE_SLOTS(typo, wrong case likeP0, etc.) are filtered out ofconfiguredat line 55 with no diagnostic — unlikeunused_slots(58-63), which does warn when a valid configured slot has no marker. A misconfigured key currently fails silently, which is harder to debug than the other failure modes this function already handles gracefully.♻️ Suggested diff
- configured = { - slot: path.strip() - for slot, path in (includes or {}).items() - if slot in PROMPT_FILE_INCLUDE_SLOTS and isinstance(path, str) and path.strip() - } + raw_includes = includes or {} + invalid_slots = sorted( + slot for slot in raw_includes if slot not in PROMPT_FILE_INCLUDE_SLOTS + ) + if invalid_slots: + logger.warning( + "[Prompt] 已配置的文件插槽名称无效,已忽略: %s", ", ".join(invalid_slots) + ) + configured = { + slot: path.strip() + for slot, path in raw_includes.items() + if slot in PROMPT_FILE_INCLUDE_SLOTS and isinstance(path, str) and path.strip() + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Undefined/ai/prompts/file_includes.py` around lines 52 - 63, Update the include-slot validation around the configured comprehension to detect keys not present in PROMPT_FILE_INCLUDE_SLOTS and emit a logger.warning diagnostic for them before filtering or skipping them. Preserve the existing configured handling for valid string paths and the unused_slots warning for valid slots without markers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/message-batching.md`:
- Line 42: Update the prompt-building description in the documented section to
describe local include files as occupying stable, fixed positions or slots
rather than being fixed system-prompt content. Preserve the existing ordering
and per-request reread behavior, and avoid wording that implies their contents
are immutable or exempt from reloads.
In `@src/Undefined/config/domain_parsers.py`:
- Around line 270-273: Update the prompt.file_includes parsing near prompt_raw
and includes_raw to log a warning when includes_raw is present but is not a
dict, while retaining the existing empty-dict fallback. Use the module’s
established logging mechanism and include the invalid value type in the warning.
In `@src/Undefined/utils/tool_calls.py`:
- Around line 28-29: Update _JSON_FUNCTION_MARKER_RE and _has_json_tool_marker()
so tool-call envelope detection recognizes a "function" member regardless of its
position among JSON keys, including malformed envelopes that should raise
TextToolCallParseError. Preserve existing marker behavior for valid inputs, and
add a regression test covering a parameters-before-function payload missing its
closing brace.
---
Nitpick comments:
In `@src/Undefined/ai/prompts/file_includes.py`:
- Around line 45-69: Update apply_prompt_file_includes and its include-file
loading path to cache loaded contents by the configured file path and current
modification time. Reuse cached content when the mtime is unchanged, invalidate
it and reread the file when the mtime changes, and preserve the existing
hot-reload behavior and error handling.
- Around line 52-63: Update the include-slot validation around the configured
comprehension to detect keys not present in PROMPT_FILE_INCLUDE_SLOTS and emit a
logger.warning diagnostic for them before filtering or skipping them. Preserve
the existing configured handling for valid string paths and the unused_slots
warning for valid slots without markers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 636847fe-453d-485d-b596-db26df67d573
⛔ Files ignored due to path filters (5)
apps/undefined-chat/package-lock.jsonis excluded by!**/package-lock.jsonapps/undefined-chat/src-tauri/Cargo.lockis excluded by!**/*.lockapps/undefined-console/package-lock.jsonis excluded by!**/package-lock.jsonapps/undefined-console/src-tauri/Cargo.lockis excluded by!**/*.lockuv.lockis excluded by!**/*.lock
📒 Files selected for processing (36)
.gitignoreARCHITECTURE.mdCHANGELOG.mdREADME.mdapps/undefined-chat/package.jsonapps/undefined-chat/src-tauri/Cargo.tomlapps/undefined-chat/src-tauri/tauri.conf.jsonapps/undefined-console/package.jsonapps/undefined-console/src-tauri/Cargo.tomlapps/undefined-console/src-tauri/tauri.conf.jsonconfig.toml.exampleconfig/README.mddocs/configuration.mddocs/deployment.mddocs/development.mddocs/message-batching.mddocs/model-compatibility.mdpyproject.tomlres/prompts/undefined.xmlres/prompts/undefined_nagaagent.xmlsrc/Undefined/__init__.pysrc/Undefined/ai/prompts/builder.pysrc/Undefined/ai/prompts/file_includes.pysrc/Undefined/config/config_class.pysrc/Undefined/config/domain_parsers.pysrc/Undefined/config/hot_reload.pysrc/Undefined/config/load_sections/domains.pysrc/Undefined/config/models.pysrc/Undefined/utils/tool_calls.pytests/test_config_api.pytests/test_config_hot_reload.pytests/test_config_template_sync.pytests/test_prompt_file_includes.pytests/test_system_prompt_constraints.pytests/test_text_tool_call_fallback.pytests/test_tool_calls.py
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/Undefined/utils/tool_calls.py (1)
204-207: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAvoid treating ordinary prose as malformed tool JSON.
Because
_JSON_FUNCTION_MARKER_REis now unanchored, any non-JSON text containing both"function":and"parameters":is classified as a tool-call parse error. Constrain marker detection to a JSON-object context and add a regression test for prose containing these terms.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Undefined/utils/tool_calls.py` around lines 204 - 207, Update the marker-detection logic in the tool-call parsing condition around _JSON_FUNCTION_MARKER_RE and _JSON_PARAMETERS_MARKER_RE so unanchored matches only qualify within a JSON-object context, not ordinary prose. Preserve malformed tool JSON detection, and add a regression test covering prose that contains both “function”: and “parameters”: without being JSON.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Undefined/utils/tool_calls.py`:
- Line 28: Add explicit type annotations to the modified module-level constants:
declare _JSON_FUNCTION_MARKER_RE as re.Pattern[str] and annotate
_FUNCTION_TOOL_ENVELOPE_KEYS with its concrete set or frozenset element type.
Preserve their existing values and ensure the annotations satisfy strict mypy
checking.
In `@tests/test_prompt_file_includes.py`:
- Around line 58-85: Route all filesystem operations in
tests/test_prompt_file_includes.py lines 58-85 and 170-173 through async helpers
from Undefined.utils.io: replace Path.write_text(), Path.stat(), and os.utime()
with awaited equivalents, adding an async mtime-setting helper to
src/Undefined/utils/io.py if needed. Use the shared helpers consistently in both
the cache invalidation and hot-reload update tests, preserving their existing
assertions and behavior.
---
Outside diff comments:
In `@src/Undefined/utils/tool_calls.py`:
- Around line 204-207: Update the marker-detection logic in the tool-call
parsing condition around _JSON_FUNCTION_MARKER_RE and _JSON_PARAMETERS_MARKER_RE
so unanchored matches only qualify within a JSON-object context, not ordinary
prose. Preserve malformed tool JSON detection, and add a regression test
covering prose that contains both “function”: and “parameters”: without being
JSON.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 04e13a20-861f-4503-a2a8-fafe6b96b635
📒 Files selected for processing (12)
ARCHITECTURE.mdCHANGELOG.mddocs/configuration.mddocs/deployment.mddocs/message-batching.mdsrc/Undefined/ai/prompts/file_includes.pysrc/Undefined/config/domain_parsers.pysrc/Undefined/utils/io.pysrc/Undefined/utils/tool_calls.pytests/test_config_api.pytests/test_prompt_file_includes.pytests/test_tool_calls.py
🚧 Files skipped from review as they are similar to previous changes (6)
- docs/message-batching.md
- ARCHITECTURE.md
- src/Undefined/config/domain_parsers.py
- docs/deployment.md
- CHANGELOG.md
- docs/configuration.md
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/test_prompt_file_includes.py (1)
111-135: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winUse the shared binary write helper for the invalid UTF-8 fixture.
tests/test_prompt_file_includes.py:117still callsinvalid_path.write_bytes(b"\xff")directly, bypassingsrc/Undefined/utils/io.py:- invalid_path.write_bytes(b"\xff") + await write_bytes(invalid_path, b"\xff")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_prompt_file_includes.py` around lines 111 - 135, Update test_apply_prompt_file_includes_warns_and_skips_unreadable_files to create invalid.xml using the shared binary write helper from src/Undefined/utils/io.py instead of calling invalid_path.write_bytes directly, while preserving the invalid UTF-8 fixture content and all existing assertions.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@tests/test_prompt_file_includes.py`:
- Around line 111-135: Update
test_apply_prompt_file_includes_warns_and_skips_unreadable_files to create
invalid.xml using the shared binary write helper from src/Undefined/utils/io.py
instead of calling invalid_path.write_bytes directly, while preserving the
invalid UTF-8 fixture content and all existing assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: d21246f7-317b-4a17-b2f0-015985f87922
📒 Files selected for processing (4)
src/Undefined/utils/io.pysrc/Undefined/utils/tool_calls.pytests/test_prompt_file_includes.pytests/test_tool_calls.py
变更摘要
[prompt.file_includes],可将本地 UTF-8 文件插入p0、p1、p2、p3、summary五个稳定主 Prompt 位置;配置路径与文件内容均支持热更新。config/prompts/*.local.*同时受 Git 忽略和 wheel/sdist 构建排除保护,公开许可证与仓库信息仍保留在主 Prompt。{"function":"end","parameters":{...}}文本 Tool Call 后备格式,并复用既有权限检查、原生执行和续轮回放链路。影响与兼容性
[prompt.file_includes]时行为保持不变,所有插槽默认为空。function/parameters封包采用严格字段和对象校验,不放宽普通文本或额外字段的执行边界。验证
uv run --no-sync pytest tests/test_prompt_file_includes.py tests/test_config_api.py tests/test_config_hot_reload.py tests/test_config_template_sync.py tests/test_system_prompt_constraints.py(88 passed)uv run --no-sync pytest tests/test_tool_calls.py tests/test_text_tool_call_fallback.py(120 passed)uv run --no-sync pytest tests/test_bump_version_script.py tests/test_release_notes_script.py(17 passed)uv run --no-sync ruff check .uv run --no-sync ruff format --check .uv run --no-sync mypy .uv run --no-sync python scripts/release_notes.py validate --tag v3.11.0uv build --wheel --offlinecd apps/undefined-console && npm run checkcd apps/undefined-chat && npm run check(453 个前端测试、73 个 Rust 测试通过)关联问题
Summary by CodeRabbit
function/parametersformats.