返回 DeepSeek-Reasonix
updategoal.go
根目录 / internal / tool / builtin / updategoal.go
1 package builtin
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "strings"
8
9 goaldomain "reasonix/internal/goal"
10 "reasonix/internal/tool"
11 )
12
13 func init() { tool.RegisterBuiltin(updateGoal{}) }
14
15 type updateGoal struct{}
16
17 func (updateGoal) Name() string { return "update_goal" }
18 func (updateGoal) Description() string {
19 return "Update the exact current goal revision. edit, pause, and resume require current direct-human authority; complete and blocked are also allowed during the exact autonomous goal round. There is no continue action: leaving an active goal unchanged continues it automatically."
20 }
21 func (updateGoal) Schema() json.RawMessage {
22 return json.RawMessage(`{"type":"object","additionalProperties":false,"properties":{"goal_id":{"type":"string","minLength":1},"revision":{"type":"integer","minimum":1},"action":{"type":"string","enum":["edit","pause","resume","complete","blocked"]},"objective":{"type":"string","minLength":1,"description":"Replacement objective; valid only for edit."},"max_goal_rounds":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Replacement limit for edit; null removes the limit."},"blocked_reason":{"type":"string","minLength":1,"description":"Concrete blocker; required only for blocked."}},"required":["goal_id","revision","action"]}`)
23 }
24 func (updateGoal) ReadOnly() bool { return false }
25 func (updateGoal) ProviderVisible(ctx context.Context) bool {
26 _, ok := tool.GoalLifecycleFromContext(ctx)
27 return ok
28 }
29 func (updateGoal) Execute(ctx context.Context, args json.RawMessage) (string, error) {
30 if strings.Contains(string(args), `"status"`) && !strings.Contains(string(args), `"action"`) {
31 return "", fmt.Errorf("legacy update_goal protocol is unsupported; call get_goal, then use goal_id, revision, and action; leaving an active goal unchanged continues automatically")
32 }
33 var input struct {
34 GoalID string `json:"goal_id"`
35 Revision uint64 `json:"revision"`
36 Action tool.GoalAction `json:"action"`
37 Objective *string `json:"objective"`
38 Limit optionalRoundLimit `json:"max_goal_rounds"`
39 BlockedReason *string `json:"blocked_reason"`
40 }
41 if err := decodeGoalArgs(args, &input, "update_goal"); err != nil {
42 return "", err
43 }
44 input.GoalID = strings.TrimSpace(input.GoalID)
45 if input.GoalID == "" || input.Revision == 0 {
46 return "", fmt.Errorf("goal_id and a positive revision are required")
47 }
48 request := tool.GoalUpdateRequest{Ref: goaldomain.Ref{ID: input.GoalID, Revision: input.Revision}, Action: input.Action}
49 switch input.Action {
50 case tool.GoalActionEdit:
51 if input.BlockedReason != nil || (input.Objective == nil && !input.Limit.Present) {
52 return "", fmt.Errorf("edit requires objective and/or max_goal_rounds and does not accept blocked_reason")
53 }
54 if input.Objective != nil {
55 value, err := trimmedRequired(*input.Objective, "objective")
56 if err != nil {
57 return "", err
58 }
59 request.Objective = &value
60 }
61 if input.Limit.Present {
62 limit, err := parseRoundLimit(input.Limit.Raw)
63 if err != nil {
64 return "", err
65 }
66 request.MaxGoalRounds = goaldomain.RoundLimitChange{Set: true, Value: limit}
67 }
68 case tool.GoalActionBlocked:
69 if input.Objective != nil || input.Limit.Present || input.BlockedReason == nil {
70 return "", fmt.Errorf("blocked requires blocked_reason and does not accept edit fields")
71 }
72 message, err := trimmedRequired(*input.BlockedReason, "blocked_reason")
73 if err != nil {
74 return "", err
75 }
76 request.BlockedReason = &goaldomain.BlockReason{Code: "model-blocked", Message: message}
77 case tool.GoalActionPause, tool.GoalActionResume, tool.GoalActionComplete:
78 if input.Objective != nil || input.Limit.Present || input.BlockedReason != nil {
79 return "", fmt.Errorf("%s does not accept objective, max_goal_rounds, or blocked_reason", input.Action)
80 }
81 default:
82 return "", fmt.Errorf("action must be one of edit|pause|resume|complete|blocked")
83 }
84 binding, err := goalBinding(ctx)
85 if err != nil {
86 return "", err
87 }
88 view, err := binding.Owner.UpdateGoal(ctx, request, binding.Authority)
89 if err != nil {
90 return "", goalToolError("update_goal", err)
91 }
92 instruction := ""
93 if view.Phase == goaldomain.PhaseComplete || view.Phase == goaldomain.PhaseBlocked {
94 instruction = "Finish the current turn with an accurate final summary for the user; no further automatic goal round will be admitted."
95 }
96 return goalToolResultWithInstruction(&view, instruction)
97 }
98
98 lines GO