Skip to content

fix(prompts): refuse to delete the active (bound) prompt version#6208

Merged
houko merged 7 commits into
mainfrom
feat/6195-prompts-add-delete
Jun 19, 2026
Merged

fix(prompts): refuse to delete the active (bound) prompt version#6208
houko merged 7 commits into
mainfrom
feat/6195-prompts-add-delete

Conversation

@houko

@houko houko commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

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_id binds it to one agent; hand-role agents use the same store). The only "bound" signal is the version's is_active flag. The dashboard hid the delete button when is_active, but PromptStore::delete_version deleted 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.rsdelete_version now SELECT is_active first and rejects an active version with LibreFangError::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 to KernelOpError::Internal (500); propagate the typed error so InvalidState surfaces as 400 via the existing kernel_op_status map.

Frontend

  • PromptsPage.tsx and PromptsExperimentsModal.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_active added to en / 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:

pnpm typecheck                                  # clean
pnpm exec vitest run src/pages/PromptsPage.test.tsx   # 10 passed
pnpm build                                      # ✓

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 cargo build could not run). The change is type-checked by hand: the query_row(...).optional()? chain yields Option<bool>, InvalidState { current, operation } matches the variant, and the kernel handle returns the store's Result directly (KernelOpError is an alias of LibreFangError, same type). CI is the verifiercargo test -p librefang-memory (store guard) and cargo test -p librefang-api + cargo check --workspace --lib on the lanes.

Note: the API integration harness (prompts_routes_integration.rs) uses a mock kernel with no real PromptStore, so it cannot exercise the store guard — the store unit test is the meaningful backend coverage.

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
@github-actions github-actions Bot added size/L 250-999 lines changed area/docs Documentation and guides area/kernel Core kernel (scheduling, RBAC, workflows) labels Jun 18, 2026
@github-actions github-actions Bot added size/M 50-249 lines changed and removed size/L 250-999 lines changed labels Jun 18, 2026
claude and others added 3 commits June 18, 2026 06:42
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.
@github-actions github-actions Bot added size/L 250-999 lines changed has-conflicts PR has merge conflicts that need resolution and removed size/M 50-249 lines changed labels Jun 18, 2026
# Conflicts:
#	.secrets.baseline
@cloudflare-workers-and-pages

Copy link
Copy Markdown

@houko
houko enabled auto-merge (squash) June 19, 2026 04:50
@github-actions github-actions Bot added size/M 50-249 lines changed and removed size/L 250-999 lines changed labels Jun 19, 2026
@github-actions github-actions Bot added ready-for-review PR is ready for maintainer review and removed has-conflicts PR has merge conflicts that need resolution labels Jun 19, 2026
@houko
houko merged commit 9e60592 into main Jun 19, 2026
34 checks passed
@houko
houko deleted the feat/6195-prompts-add-delete branch June 19, 2026 07:21
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation and guides area/kernel Core kernel (scheduling, RBAC, workflows) ready-for-review PR is ready for maintainer review size/M 50-249 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

提示词要有 新增 和删除功能

2 participants