返回 DeepSeek-Reasonix
prompt.go
根目录 / internal / goal / prompt.go
1 package goal
2
3 import (
4 "encoding/json"
5 "fmt"
6 )
7
8 type continuationEnvelope struct {
9 GoalID string `json:"goalId"`
10 Revision uint64 `json:"revision"`
11 Objective string `json:"objective"`
12 Round uint64 `json:"round"`
13 MaxGoalRounds *uint64 `json:"maxGoalRounds"`
14 }
15
16 type recoveryEnvelope struct {
17 GoalID string `json:"goalId"`
18 Revision uint64 `json:"revision"`
19 Objective string `json:"objective"`
20 Phase Phase `json:"phase"`
21 Activation Activation `json:"activation"`
22 RoundsStarted uint64 `json:"roundsStarted"`
23 StopReason string `json:"stopReason,omitempty"`
24 }
25
26 // ContinuationPrompt renders dynamic goal state into a one-shot user message.
27 // It must never be inserted into the system prompt: keeping the stable prefix
28 // unchanged preserves provider prompt-cache reuse across autonomous rounds.
29 func ContinuationPrompt(view View) (string, error) {
30 if view.Phase != PhaseActive || view.Activation != ActivationArmed {
31 return "", goalError(ErrInvalidTransition, "goal is not eligible for continuation")
32 }
33 payload, err := json.Marshal(continuationEnvelope{
34 GoalID: view.ID,
35 Revision: view.Revision,
36 Objective: view.Objective,
37 Round: view.RoundsStarted + 1,
38 MaxGoalRounds: cloneLimit(view.MaxGoalRounds),
39 })
40 if err != nil {
41 return "", fmt.Errorf("encode goal continuation: %w", err)
42 }
43 return "Continue making concrete progress on the current goal. Verify the work you perform.\n\n" +
44 "<goal-round>\n" + string(payload) + "\n</goal-round>\n\n" +
45 "Call get_goal before update_goal and use its exact goal_id and revision. " +
46 "Mark complete only when the whole objective is done. If useful work remains, leave the goal active; " +
47 "do not treat a round summary as completion. Mark blocked only for a concrete persistent blocker.", nil
48 }
49
50 // RecoveryPrompt renders an existing recoverable goal into the visible user
51 // turn tail. Paused goals are deliberately excluded: only an explicit host UI
52 // or command may undo a user pause.
53 func RecoveryPrompt(view View) (string, error) {
54 if view.Phase != PhaseBlocked && !(view.Phase == PhaseActive && view.Activation == ActivationDisarmed) {
55 return "", goalError(ErrInvalidTransition, "goal is not eligible for user-authorized recovery")
56 }
57 payload, err := json.Marshal(recoveryEnvelope{
58 GoalID: view.ID, Revision: view.Revision, Objective: view.Objective,
59 Phase: view.Phase, Activation: view.Activation,
60 RoundsStarted: view.RoundsStarted, StopReason: view.StopReason,
61 })
62 if err != nil {
63 return "", fmt.Errorf("encode goal recovery: %w", err)
64 }
65 return "An existing long-running goal is waiting for recovery. Interpret the user's request in that context; do not replace the objective with the text of this turn.\n\n" +
66 "<goal-recovery>\n" + string(payload) + "\n</goal-recovery>\n\n" +
67 "If the user is asking to continue: Call get_goal and then update_goal with action resume using the exact goal_id and revision. " +
68 "A user-paused goal may only be resumed through an explicit host UI or command.", nil
69 }
70
70 lines GO