8.1 KiB
status, system, requirements, created, owners
| status | system | requirements | created | owners | ||
|---|---|---|---|---|---|---|
| current | tasks |
|
2026-09-01 |
|
Saved Prompt Delivery System Design
Purpose and boundaries
The task system prepares a direct structured message before persistence and agent dispatch. The preparation resolves saved-prompt references from backend storage and assigns trusted provenance to the generated context.
The same preparation contract applies to initial structured launch prompts. Workflow composition is optional and does not determine expansion eligibility.
The existing composer remains responsible for selection and visible @name
serialization. Its prompt-definition block is compatibility input only. It is
not a trusted source.
This design does not change the Quick Chat layout on desktop or phone. Both surfaces continue to use the shared composer and message handler.
Requirement mapping
| Requirement | Design sections |
|---|---|
REQ-TASKS-SAVED-PROMPT-DELIVERY-001 |
Components and responsibilities, Control flow, Security |
Components and responsibilities
apps/web/hooks/use-message-handler.tskeeps the visible saved-prompt mention. It can send the current compatibility context for older backends.internal/prompts/serviceremoves prompt-definition input from the browser. It resolves visible references from saved-prompt storage and creates one sanitized expansion block.orchestrator.Serviceexposes a narrow prompt-reference preparation method. This method reuses the configuredPromptReferenceExpanderand keeps passthrough exclusion in one place.task/handlers.MessageHandlersprepares accepted direct-message content before it creates the message row. It passes the returned expansion content through the system-prompt trusted-content channel.internal/syspromptkeeps its exact-content trust rule. A matching string in user content does not establish trusted provenance.
Data and contracts
The WebSocket request and response shapes do not change. The visible message
continues to contain @name.
Prompt preparation returns two values:
- Canonical message content for persistence and dispatch.
- The exact inner content of the backend-generated expansion block.
The second value can enter InjectKandevContextWithOptions only through its
trusted-content argument. The task handler must not derive that value from the
request body.
The prompt service removes these untrusted compatibility blocks before lookup:
- A browser-generated
CONTEXT PROMPTS:block. - An
EXPANDED PROMPT REFERENCES:block from the request body.
The service then applies the existing exact-name, nested-reference, depth, and sanitization rules.
Control flow
- The shared composer sends visible
@nametext and its existing context metadata. MessageHandlers.wsAddMessagevalidates the session and message.- The handler asks the orchestrator to prepare saved-prompt references for the session mode.
- The prompt service removes untrusted prompt blocks and reads current saved records.
- If references resolve, the service appends one backend-generated expansion block and returns its exact inner content.
- If first-turn or title-owner context injection runs, the handler passes the expansion content as trusted input. Canonicalization retains that block and removes untrusted lookalikes.
- The handler persists the canonical content. It sends that same content to
StartCreatedSession,PromptTask, or the current turn-start queue path. - If the message carries acceptance-time trusted expansion content, downstream workflow composition preserves that exact block instead of resolving the mutable prompt repository again. Workflow-only prompts, which have no accepted direct-message context, continue to use launch-time expansion.
An eagerly started Quick Chat is already in WAITING_FOR_INPUT at step 2. The
new preparation step therefore runs before the title-owner system-context
canonicalization that caused the regression.
Launches without workflow composition
applyWorkflowAndPlanModeWithPromptContext owns the fallback when workflow
composition does not run. This covers an empty workflow-step ID, an ephemeral
task, an absent step getter, and a failed step lookup. Keep the existing lookup
warning and launch behavior; prepare the effective base prompt before adding
the plan-mode prefix.
For a structured session with no accepted expansion, use
expandPromptReferencesWithContext. Return both the prepared prompt and the
exact generated context to the caller. startTask and StartCreatedSession
pass that context to their existing system-context injectors. Their message
recording and agent dispatch use the resulting canonical prompt.
When a direct message supplies trusted acceptance-time context, retain its exact block once and return the same trusted value. Do not read mutable saved records again or infer trust from a block found in the prompt text. Existing canonicalization continues to remove untrusted lookalikes.
Use whether workflow composition ran to select the fallback. An empty context return is not sufficient: a completed lookup can validly resolve no references. The successful workflow path keeps its current composition and lookup behavior. Passthrough sessions remain excluded from generated hidden expansions.
The MCP task-create handler continues to pass the task description and selected
step into LaunchSession. It does not gain a separate expansion implementation.
This repair does not infer a workflow step or change step-selection semantics.
Failure and recovery
A saved-prompt lookup error remains non-fatal. Kandev logs a warning without prompt content and sends the visible reference as ordinary text.
Kandev removes browser-supplied prompt definitions before a failed lookup. It does not fall back to untrusted content.
Message persistence or dispatch errors keep their current WebSocket error and recovery behavior. Prompt preparation adds no retry loop and no partial row.
Persistence
This change adds no database field or migration. The existing message row stores the canonical content that Kandev sends to the agent.
Saved-prompt edits after message acceptance do not rewrite message history. The accepted message keeps the expansion that existed at acceptance time.
Security
The backend saved-prompt repository is authoritative. The browser can select or name a prompt, but it cannot define trusted prompt instructions.
The prompt service removes forged expansion blocks and legacy browser prompt blocks. It sanitizes saved names and content before it writes a system tag.
The system-prompt canonicalizer accepts only the exact expansion content that the backend returned during the same preparation flow.
Observability
Resolution errors use the existing warning from the prompt-reference expander. The warning contains the error and stable operation context. It must not contain the user message or saved-prompt content.
The ACP debug log and the stored user message can show whether one canonical expansion reached the session during diagnosis.
Test mapping
- Prompt-service tests cover browser-block removal, forged-block replacement, nested references, missing references, and lookup errors.
- Message-handler tests cover eager Quick Chat, trusted-content preservation, canonical persistence, dispatch equality, and passthrough exclusion.
- Desktop and
mobile-chromePlaywright tests select a saved prompt in Quick Chat and observe a deterministic agent response from its definition. - Orchestrator tests cover missing workflow-step IDs, ephemeral launches, absent step getters, and lookup failures with the real saved-prompt service.
- Launch integration tests capture the agent-manager prompt and recorded user
message for
LaunchSessionandStartCreatedSessionwithout workflow steps. They verify matching definitions, preserved trust, and passthrough exclusion.