[PR #301] [MERGED] fix: apply custom prompts to new sessions #306

Closed
opened 2026-06-06 22:10:08 -04:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/vxcontrol/pentagi/pull/301
Author: @mason5052
Created: 5/6/2026
Status: Merged
Merged: 5/21/2026
Merged by: @asdek

Base: feature/next-releaseHead: codex/issue-300-custom-prompts


📝 Commits (3)

  • 08c050c fix: apply custom prompts to new sessions
  • 3278c62 fix(controller): avoid JSON round-trip and N+1 prompter loads
  • 19b63c5 Merge branch 'feature/next-release' into codex/issue-300-custom-prompts

📊 Changes

5 files changed (+306 additions, -12 deletions)

View changed files

📝 backend/pkg/controller/assistant.go (+17 -2)
📝 backend/pkg/controller/flow.go (+9 -3)
backend/pkg/controller/prompter.go (+50 -0)
backend/pkg/controller/prompter_test.go (+209 -0)
📝 backend/pkg/templates/templates.go (+21 -7)

📄 Description

Summary

Custom system prompts saved via the Settings -> Prompts UI are now applied to newly created assistant and flow sessions. Prior to this change, every session creation path used templates.NewDefaultPrompter() (with a leftover TODO comment), so user customizations never reached the agents and Langfuse traces always showed the default templates.

Problem

backend/pkg/controller/assistant.go (NewAssistantWorker, LoadAssistantWorker) and backend/pkg/controller/flow.go (NewFlowWorker, LoadFlowWorker) all built the prompter from templates.NewDefaultPrompter() and ignored the per-user prompts table that the Prompts UI persists. The Custom badge in the UI was therefore decorative -- saved overrides had no effect on subsequent sessions.

Solution

Introduce a small controller-side helper, newUserPrompter, which:

  1. Loads the user's saved prompts via database.Querier.GetUserPrompts.
  2. Loads the compiled defaults via templates.LoadDefaultPromptsMap() (a new helper that returns the embedded defaults as a PromptsMap directly, avoiding a JSON round-trip) and overlays each non-empty user override onto the resulting map.
  3. Returns a templates.NewFlowPrompter(merged) so prompt types the user never customized continue to resolve to the defaults.

A database error fails session creation explicitly (wrapErrorEndSpan on the existing langfuse span) instead of silently falling back to defaults. Empty bodies are skipped because the UI uses delete (or reset, which writes the default body back) to remove a customization, so an empty row is unexpected and would otherwise surface as ErrTemplateNotFound deep inside agent rendering.

The helper lives in pkg/controller rather than pkg/templates to avoid creating a new templates -> database import edge.

To avoid an N+1 pattern on flow load, assistantWorkerCtx carries an optional prompter field. LoadFlowWorker builds the user prompter once for the flow and reuses it across every assistant in that flow; LoadAssistantWorker falls back to building its own prompter when invoked outside a flow load.

Lifecycle Semantics

  • The user prompter is snapshotted at session creation time (NewFlowWorker, LoadFlowWorker, NewAssistantWorker, standalone LoadAssistantWorker).
  • Customizations edited mid-session are not applied retroactively to running sessions; only sessions created or loaded after the edit pick them up. This matches the existing per-session lifecycle of every other agent setting and is intentional -- live mutation of the prompter would race with in-flight agent calls.
  • Within a single flow load, all assistants share the same snapshot, so every assistant in a given flow sees a consistent set of prompts even if the user edits between assistants.

User Impact

  • New assistant and flow sessions now use the saved custom prompts for each PromptType the user has overridden.
  • Sessions for users who have not customized any prompts behave exactly as before.
  • No GraphQL schema, REST API, database migration, or frontend change.

Test Plan

  • go test ./pkg/controller/... ./pkg/templates/... (passes locally on Go 1.24)
  • New unit tests in backend/pkg/controller/prompter_test.go cover:
    • No user prompts -> defaults preserved
    • Single override -> custom body returned, unrelated types still default
    • Partial overrides on multiple types -> overridden types custom, others default
    • Empty body row -> default preserved (override skipped)
    • DB error from GetUserPrompts -> wrapped error propagated, nil prompter returned
    • Happy path through newUserPrompter end-to-end with a fake database.Querier

Follow-ups

  • backend/cmd/ftester/worker/tester.go carries the same TODO and was intentionally left alone here -- it is a developer harness rather than a session creation path. Happy to fold it in if reviewers prefer one place.

Closes #300


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/vxcontrol/pentagi/pull/301 **Author:** [@mason5052](https://github.com/mason5052) **Created:** 5/6/2026 **Status:** ✅ Merged **Merged:** 5/21/2026 **Merged by:** [@asdek](https://github.com/asdek) **Base:** `feature/next-release` ← **Head:** `codex/issue-300-custom-prompts` --- ### 📝 Commits (3) - [`08c050c`](https://github.com/vxcontrol/pentagi/commit/08c050ce216dbcd9e4e06da21c83abfa65d3d2af) fix: apply custom prompts to new sessions - [`3278c62`](https://github.com/vxcontrol/pentagi/commit/3278c62b965fc75446d02f0460968ef1f802d81c) fix(controller): avoid JSON round-trip and N+1 prompter loads - [`19b63c5`](https://github.com/vxcontrol/pentagi/commit/19b63c5b45f07a2e869b1745a4727b8403aefecb) Merge branch 'feature/next-release' into codex/issue-300-custom-prompts ### 📊 Changes **5 files changed** (+306 additions, -12 deletions) <details> <summary>View changed files</summary> 📝 `backend/pkg/controller/assistant.go` (+17 -2) 📝 `backend/pkg/controller/flow.go` (+9 -3) ➕ `backend/pkg/controller/prompter.go` (+50 -0) ➕ `backend/pkg/controller/prompter_test.go` (+209 -0) 📝 `backend/pkg/templates/templates.go` (+21 -7) </details> ### 📄 Description ## Summary Custom system prompts saved via the Settings -> Prompts UI are now applied to newly created assistant and flow sessions. Prior to this change, every session creation path used `templates.NewDefaultPrompter()` (with a leftover TODO comment), so user customizations never reached the agents and Langfuse traces always showed the default templates. ## Problem `backend/pkg/controller/assistant.go` (`NewAssistantWorker`, `LoadAssistantWorker`) and `backend/pkg/controller/flow.go` (`NewFlowWorker`, `LoadFlowWorker`) all built the prompter from `templates.NewDefaultPrompter()` and ignored the per-user `prompts` table that the Prompts UI persists. The Custom badge in the UI was therefore decorative -- saved overrides had no effect on subsequent sessions. ## Solution Introduce a small controller-side helper, `newUserPrompter`, which: 1. Loads the user's saved prompts via `database.Querier.GetUserPrompts`. 2. Loads the compiled defaults via `templates.LoadDefaultPromptsMap()` (a new helper that returns the embedded defaults as a `PromptsMap` directly, avoiding a JSON round-trip) and overlays each non-empty user override onto the resulting map. 3. Returns a `templates.NewFlowPrompter(merged)` so prompt types the user never customized continue to resolve to the defaults. A database error fails session creation explicitly (`wrapErrorEndSpan` on the existing langfuse span) instead of silently falling back to defaults. Empty bodies are skipped because the UI uses delete (or reset, which writes the default body back) to remove a customization, so an empty row is unexpected and would otherwise surface as `ErrTemplateNotFound` deep inside agent rendering. The helper lives in `pkg/controller` rather than `pkg/templates` to avoid creating a new `templates -> database` import edge. To avoid an N+1 pattern on flow load, `assistantWorkerCtx` carries an optional `prompter` field. `LoadFlowWorker` builds the user prompter once for the flow and reuses it across every assistant in that flow; `LoadAssistantWorker` falls back to building its own prompter when invoked outside a flow load. ## Lifecycle Semantics - The user prompter is **snapshotted at session creation time** (`NewFlowWorker`, `LoadFlowWorker`, `NewAssistantWorker`, standalone `LoadAssistantWorker`). - Customizations edited mid-session are **not** applied retroactively to running sessions; only sessions created or loaded after the edit pick them up. This matches the existing per-session lifecycle of every other agent setting and is intentional -- live mutation of the prompter would race with in-flight agent calls. - Within a single flow load, all assistants share the same snapshot, so every assistant in a given flow sees a consistent set of prompts even if the user edits between assistants. ## User Impact - New assistant and flow sessions now use the saved custom prompts for each `PromptType` the user has overridden. - Sessions for users who have not customized any prompts behave exactly as before. - No GraphQL schema, REST API, database migration, or frontend change. ## Test Plan - [x] `go test ./pkg/controller/... ./pkg/templates/...` (passes locally on Go 1.24) - [x] New unit tests in `backend/pkg/controller/prompter_test.go` cover: - No user prompts -> defaults preserved - Single override -> custom body returned, unrelated types still default - Partial overrides on multiple types -> overridden types custom, others default - Empty body row -> default preserved (override skipped) - DB error from `GetUserPrompts` -> wrapped error propagated, nil prompter returned - Happy path through `newUserPrompter` end-to-end with a fake `database.Querier` ## Follow-ups - `backend/cmd/ftester/worker/tester.go` carries the same TODO and was intentionally left alone here -- it is a developer harness rather than a session creation path. Happy to fold it in if reviewers prefer one place. Closes #300 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-06-06 22:10:08 -04:00
yindo closed this issue 2026-06-06 22:10:08 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vxcontrol/pentagi#306