Skip to content

feat(prompt): add hot-reloadable local customization - #90

Merged
69gg merged 7 commits into
mainfrom
feature/better-prompt
Jul 31, 2026
Merged

feat(prompt): add hot-reloadable local customization#90
69gg merged 7 commits into
mainfrom
feature/better-prompt

Conversation

@69gg

@69gg 69gg commented Jul 30, 2026

Copy link
Copy Markdown
Owner

变更摘要

  • 新增 [prompt.file_includes],可将本地 UTF-8 文件插入 p0p1p2p3summary 五个稳定主 Prompt 位置;配置路径与文件内容均支持热更新。
  • 将部署者私有身份与权限规则从受版本控制的主 Prompt 拆分到本地文件;config/prompts/*.local.* 同时受 Git 忽略和 wheel/sdist 构建排除保护,公开许可证与仓库信息仍保留在主 Prompt。
  • 兼容 {"function":"end","parameters":{...}} 文本 Tool Call 后备格式,并复用既有权限检查、原生执行和续轮回放链路。
  • 同步 README、配置/部署/架构/模型兼容文档,并将项目版本更新至 v3.11.0。

影响与兼容性

  • 未配置 [prompt.file_includes] 时行为保持不变,所有插槽默认为空。
  • 插槽文件缺失、不可读或不是 UTF-8 时记录警告并跳过,不中断请求;文件只展开一轮。
  • Git/构建排除只防止本地文件被提交或打包,插入后的内容仍会发送给当前模型供应商。
  • function / parameters 封包采用严格字段和对象校验,不放宽普通文本或额外字段的执行边界。
  • 无 UI 布局变更,无需截图。

验证

  • 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.0
  • uv build --wheel --offline
  • cd apps/undefined-console && npm run check
  • cd apps/undefined-chat && npm run check(453 个前端测试、73 个 Rust 测试通过)

关联问题

  • 无。

Summary by CodeRabbit

  • New Features
    • Added local main-prompt customization through configurable P0–P3 and summary slots.
    • Added hot-updated local prompt files with mtime-based caching.
    • Improved text tool-call compatibility with function/parameters formats.
  • Documentation
    • Expanded configuration, deployment, and architecture guidance.
  • Bug Fixes
    • Improved handling of missing, unreadable, or invalid prompt files and configuration.
  • Chores
    • Updated the release to version 3.11.0 and excluded local overrides from build artifacts.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8b34009c-d503-48bc-bc8e-182ebcfd6f8a

📥 Commits

Reviewing files that changed from the base of the PR and between 9268429 and a6964f3.

📒 Files selected for processing (1)
  • tests/test_prompt_file_includes.py

📝 Walkthrough

Walkthrough

This 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 function/parameters envelopes. Versions are synchronized to 3.11.0.

Changes

Prompt customization

Layer / File(s) Summary
Prompt include configuration
config.toml.example, src/Undefined/config/*, tests/test_config_*
Defines fixed prompt slots, parses configured paths, and propagates changes through runtime hot reload.
Prompt file injection and reload
src/Undefined/ai/prompts/*, src/Undefined/utils/io.py, tests/test_prompt_file_includes.py, tests/test_system_prompt_constraints.py
Loads configured UTF-8 files, substitutes prompt markers, handles read failures, and verifies content and path updates on later builds.
Prompt resource modularization and rule updates
res/prompts/*, tests/test_system_prompt_constraints.py
Adds stable include markers and revises identity, privacy, conversation, memory, and prompt-injection guidance.
Prompt include documentation and release support
docs/*, config/*, pyproject.toml, .gitignore, application manifests, CHANGELOG.md
Documents slot and deployment behavior, excludes local override files from artifacts, and synchronizes version metadata to 3.11.0.

Text tool-call compatibility

Layer / File(s) Summary
Function/parameters envelope parsing
src/Undefined/utils/tool_calls.py
Recognizes and converts function/parameters JSON envelopes into internal tool calls while validating allowed keys.
Tool-call compatibility tests and documentation
docs/model-compatibility.md, tests/test_tool_calls.py, tests/test_text_tool_call_fallback.py
Covers object and stringified parameters, mixed envelope styles, invalid payloads, and fallback replay.

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
Loading

Possibly related PRs

  • 69gg/Undefined#79: Both modify PromptBuilder and prompt configuration to inject dynamic content.
  • 69gg/Undefined#84: Both modify PromptBuilder behavior during prompt assembly.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding hot-reloadable local prompt customization.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/better-prompt

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/Undefined/ai/prompts/file_includes.py (2)

45-69: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider mtime-based caching to avoid re-reading include files on every request.

apply_prompt_file_includes is invoked from build_messages on every AI request (per builder.py lines 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 win

Unrecognized/invalid slot keys are silently dropped without a warning.

Slots not in PROMPT_FILE_INCLUDE_SLOTS (typo, wrong case like P0, etc.) are filtered out of configured at line 55 with no diagnostic — unlike unused_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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b41ab8 and 8ebcf94.

⛔ Files ignored due to path filters (5)
  • apps/undefined-chat/package-lock.json is excluded by !**/package-lock.json
  • apps/undefined-chat/src-tauri/Cargo.lock is excluded by !**/*.lock
  • apps/undefined-console/package-lock.json is excluded by !**/package-lock.json
  • apps/undefined-console/src-tauri/Cargo.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (36)
  • .gitignore
  • ARCHITECTURE.md
  • CHANGELOG.md
  • README.md
  • apps/undefined-chat/package.json
  • apps/undefined-chat/src-tauri/Cargo.toml
  • apps/undefined-chat/src-tauri/tauri.conf.json
  • apps/undefined-console/package.json
  • apps/undefined-console/src-tauri/Cargo.toml
  • apps/undefined-console/src-tauri/tauri.conf.json
  • config.toml.example
  • config/README.md
  • docs/configuration.md
  • docs/deployment.md
  • docs/development.md
  • docs/message-batching.md
  • docs/model-compatibility.md
  • pyproject.toml
  • res/prompts/undefined.xml
  • res/prompts/undefined_nagaagent.xml
  • src/Undefined/__init__.py
  • src/Undefined/ai/prompts/builder.py
  • src/Undefined/ai/prompts/file_includes.py
  • src/Undefined/config/config_class.py
  • src/Undefined/config/domain_parsers.py
  • src/Undefined/config/hot_reload.py
  • src/Undefined/config/load_sections/domains.py
  • src/Undefined/config/models.py
  • src/Undefined/utils/tool_calls.py
  • tests/test_config_api.py
  • tests/test_config_hot_reload.py
  • tests/test_config_template_sync.py
  • tests/test_prompt_file_includes.py
  • tests/test_system_prompt_constraints.py
  • tests/test_text_tool_call_fallback.py
  • tests/test_tool_calls.py

Comment thread docs/message-batching.md Outdated
Comment thread src/Undefined/config/domain_parsers.py
Comment thread src/Undefined/utils/tool_calls.py Outdated
@69gg

69gg commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@69gg

69gg commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Avoid treating ordinary prose as malformed tool JSON.

Because _JSON_FUNCTION_MARKER_RE is 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8ebcf94 and 2f07a0c.

📒 Files selected for processing (12)
  • ARCHITECTURE.md
  • CHANGELOG.md
  • docs/configuration.md
  • docs/deployment.md
  • docs/message-batching.md
  • src/Undefined/ai/prompts/file_includes.py
  • src/Undefined/config/domain_parsers.py
  • src/Undefined/utils/io.py
  • src/Undefined/utils/tool_calls.py
  • tests/test_config_api.py
  • tests/test_prompt_file_includes.py
  • tests/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

Comment thread src/Undefined/utils/tool_calls.py Outdated
Comment thread tests/test_prompt_file_includes.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Use the shared binary write helper for the invalid UTF-8 fixture.

tests/test_prompt_file_includes.py:117 still calls invalid_path.write_bytes(b"\xff") directly, bypassing src/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

📥 Commits

Reviewing files that changed from the base of the PR and between 2f07a0c and 9268429.

📒 Files selected for processing (4)
  • src/Undefined/utils/io.py
  • src/Undefined/utils/tool_calls.py
  • tests/test_prompt_file_includes.py
  • tests/test_tool_calls.py

@69gg
69gg merged commit 5a8d3ae into main Jul 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant