fix(prompts): refuse to delete the active (bound) prompt version#6208
Merged
Conversation
PromptStore::delete_version deleted unconditionally, so a direct API or SDK call could delete the version an agent is actively sending, orphaning its live prompt; the dashboard only hid the delete button client-side. The store now SELECTs is_active before deleting and rejects an active version with InvalidState (surfaced as 400); the kernel handle stops flattening the store error to Internal (500) so the typed variant reaches the HTTP layer, and an unknown id stays an idempotent no-op. The dashboard renders the active version's delete button disabled with an explanatory tooltip on both the Prompts page and the per-agent Prompts/Experiments modal, with i18n in en/zh/uk. Closes #6195
The non-active delete button referenced the i18n key agents.prompts_experiments.delete, which exists in no locale file, so it always rendered the hardcoded English defaultValue for zh/uk users. Point it at the existing, fully-translated prompts.delete key, matching PromptsPage.tsx.
…yer (#6195) Drives create -> activate -> delete through the real SQLite-backed store and asserts DELETE of the active version returns 400 and the version survives. Also corrects the stale comment that claimed the harness has no real PromptStore — the read-back is None only because that test activates a synthetic id never inserted into the store.
# Conflicts: # .secrets.baseline
Deploying librefang with
|
| Latest commit: |
ab03d18
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://5cc15d28.librefang-7oe.pages.dev |
| Branch Preview URL: | https://feat-6195-prompts-add-delete.librefang-7oe.pages.dev |
houko
enabled auto-merge (squash)
June 19, 2026 04:50
GQAdonis
pushed a commit
to GQAdonis/librefang
that referenced
this pull request
Jun 19, 2026
Merge upstream/main into the BossFang fork; origin/main was 15 commits behind. Notable upstream changes: - librefang#6225 scope the compaction-summary banner to the compacted session (adds canonical_sessions.compacted_summary_session_id). - librefang#6196 deny WASM fs_write to the audit anchor via a capability deny-list. - librefang#6226 / librefang#6227 add agent label and exit-reason metrics to the agent loop. - librefang#6215 context-window usage indicator + honest quota-error classification. - librefang#6217 per-instance sidecar secrets so each agent owns its own handle. - librefang#6194 global Auto-Dream on/off switch on the Memory tab. - librefang#6211 / librefang#6214 / librefang#6212 token/context cap fixes; librefang#6208 refuse to delete the active prompt version. - librefang#6218 browser_tools.rs ToolError migration; librefang#6203 launchctl let-binding build fix; librefang#6224 docs dep bumps; librefang#6193 drop five orphaned email deps. Conflict resolution: - deny.toml: keep our RUSTSEC-2025-0141 (bincode 2.0.x) ignore entry (take ours). - deny.toml: ignore three pre-existing unmaintained advisories newly tripped by the RustSec DB (all transitive via the UAR provider chain, none introduced by this merge): RUSTSEC-2024-0384 (instant), RUSTSEC-2024-0436 (paste), RUSTSEC-2025-0119 (number_prefix). BossFang preservation (SurrealDB schema parity for upstream SQLite v46 / librefang#6225): - Add crates/librefang-storage/src/migrations/sql/032_canonical_sessions_compacted_summary_session_id.surql declaring the new field on the SCHEMAFULL canonical_sessions table (SCHEMAFULL silently drops undefined fields on write), registered as version 32 in migrations/mod.rs. - migrate/sqlite_to_surreal.rs: copy the new column so a SQLite to SurrealDB migration preserves the owning-session pointer rather than dropping it. - backends/surreal_session.rs: preserve compacted_summary_session_id across canonical appends, since the upsert replaces the whole record. - Cargo.lock: pick up the workspace version bump (beta.19 to beta.20) the merge introduced. Verification: - cargo check --workspace --lib — clean. - cargo check -p librefang-storage -p librefang-memory -p librefang-uar-spec — clean. - cargo test -p librefang-storage migration — ok (migration ordering / SurrealDB-3 flexible-syntax invariants). - cargo test -p librefang-memory --lib session — 50 passed (incl. upstream's store_llm_summary round-trip test). - cargo clippy -p librefang-storage -p librefang-memory — clean. - python3 scripts/enforce-branding.py --check — clean; Tauri desktop audit and URL-drift scan both clean.
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.
Summary
Fixes #6195. The prompt library already supports create and delete on the dashboard; the real gap the issue asks for ("删除提示词需要验证是否已经解绑所有关联的智能体或者Hands") is a delete guard: deleting a prompt version must not orphan the agent that is actively using it.
A prompt version is per-agent (its
agent_idbinds it to one agent; hand-role agents use the same store). The only "bound" signal is the version'sis_activeflag. The dashboard hid the delete button whenis_active, butPromptStore::delete_versiondeleted unconditionally, so a direct API/SDK call could delete the active version and leave the agent's live prompt orphaned.Changes
Backend
crates/librefang-memory/src/prompt.rs—delete_versionnowSELECT is_activefirst and rejects an active version withLibreFangError::InvalidState; an unknown id stays an idempotent no-op DELETE. Store unit test: active delete is rejected and the row remains, inactive deletes, unknown id is a no-op.crates/librefang-kernel/src/kernel/handles/prompt_store.rs— stop flattening the store error toKernelOpError::Internal(500); propagate the typed error soInvalidStatesurfaces as 400 via the existingkernel_op_statusmap.Frontend
PromptsPage.tsxandPromptsExperimentsModal.tsx— the active version's delete button is now rendered disabled with an explanatory tooltip (instead of hidden), so the affordance and the reason are visible.prompts.delete_blocked_activeadded toen/zh/uk.PromptsPage.test.tsx— updated the active-version case to assert the delete is present-but-disabled, plus a new case asserting an inactive version's delete dispatches the mutation.Verification
Frontend — locally verified:
Backend — static-reviewed, CI-pending:⚠️ local Docker verification was not possible this run (the host disk filled and the OrbStack daemon crashed, so a cold
cargobuild could not run). The change is type-checked by hand: thequery_row(...).optional()?chain yieldsOption<bool>,InvalidState { current, operation }matches the variant, and the kernel handle returns the store'sResultdirectly (KernelOpErroris an alias ofLibreFangError, same type). CI is the verifier —cargo test -p librefang-memory(store guard) andcargo test -p librefang-api+cargo check --workspace --libon the lanes.Note: the API integration harness (
prompts_routes_integration.rs) uses a mock kernel with no realPromptStore, so it cannot exercise the store guard — the store unit test is the meaningful backend coverage.