返回 DeepSeek-Reasonix
policy.go
根目录 / internal / planmode / policy.go
1 package planmode
2
3 import (
4 "encoding/json"
5 "fmt"
6 "strings"
7 )
8
9 // Marker is the model-facing plan-mode instruction block. It rides in the user
10 // turn, not the system prompt or tool schema, so plan toggles preserve cache shape.
11 const LegacyWorkflowMarker = "[Plan mode — planning workflow. Gather context, ask clarifying questions with ask, maintain this turn's planning notes with todo_write when useful, and delegate focused research when useful. Do not begin implementation in this mode: avoid file writes, unsafe shell commands, capability installation, memory mutation, writer-capable delegation, or long-lived process control. This is a workflow instruction, not a permission boundary; every tool call remains governed by the active Permissions and Sandbox policy. Before planning, if a decision that is genuinely the user's — tech stack, an ambiguous requirement, scope, an irreversible choice — would materially shape the plan and you can't settle it from the codebase or a sensible default, use the ask tool to clarify it first; otherwise pick the obvious default and state the assumption in the plan instead of asking. Then present a structured plan as your reply and stop. The approved plan authorizes its scope but does not create or restore a todo list; execution writes a fresh flat todo list in its own turn when useful. The user will be asked to approve the plan before the workflow switches to implementation.]"
12
13 const Marker = "[Plan mode — planning workflow. Gather context, ask clarifying questions with ask, maintain this turn's planning notes with todo_write when useful, and delegate focused research when useful. Do not begin implementation in this mode: avoid file writes, unsafe shell commands, capability installation, memory mutation, writer-capable delegation, or long-lived process control. The host blocks state-changing actions before plan approval, including in Yolo mode. Permissions and Sandbox rules still apply. Before planning, if a decision that is genuinely the user's — tech stack, an ambiguous requirement, scope, an irreversible choice — would materially shape the plan and you can't settle it from the codebase or a sensible default, use the ask tool to clarify it first; otherwise pick the obvious default and state the assumption in the plan instead of asking. Then present a structured plan as your reply and stop. The approved plan authorizes its scope but does not create or restore a todo list; execution writes a fresh flat todo list in its own turn when useful. The user will be asked to approve the plan before the workflow switches to implementation.]"
14
15 // PlanSafety is a tool's explicit stance on whether the action belongs in the
16 // planning phase. It is deliberately not a write-safety classification: ordinary
17 // readers and writers both continue to Permissions/Sandbox.
18 type PlanSafety int
19
20 const (
21 // PlanSafetyUnknown is the default. The call continues to Permissions/Sandbox.
22 PlanSafetyUnknown PlanSafety = iota
23 // PlanSafetySafe explicitly confirms that the call makes sense while planning.
24 PlanSafetySafe
25 // PlanSafetyUnsafe opts a tool out of the planning phase even when it is
26 // side-effect-free.
27 PlanSafetyUnsafe
28 )
29
30 // Call is the plan-mode view of one tool invocation. ReadOnly and Args remain
31 // for source compatibility with older callers; they do not decide phase
32 // availability because Permissions/Sandbox own safety.
33 type Call struct {
34 Name string
35 ReadOnly bool
36 Safety PlanSafety
37 Args json.RawMessage
38 }
39
40 // Decision reports whether phase semantics refuse a call and why.
41 type Decision struct {
42 Blocked bool
43 Message string
44 }
45
46 // ReadOnlyCommandTrust is retained for source compatibility with the legacy
47 // Plan bash trust bridge. Decide no longer produces this request: bash safety is
48 // classified by Permissions, and read-only subagents enforce their own runner
49 // boundary directly.
50 type ReadOnlyCommandTrust struct {
51 Command string
52 Prefix string
53 }
54
55 // Policy is retained so existing config/assembly code can carry legacy
56 // plan_mode_* fields without breaking old data. Those fields no longer grant or
57 // revoke execution in the main Plan workflow.
58 type Policy struct {
59 AllowedTools []string
60 ReadOnlyCommands []string
61 }
62
63 // Decide applies phase semantics only. Plan is a collaboration workflow, not a
64 // security boundary: every ordinary call proceeds to the same permission and
65 // sandbox gates used outside Plan. A tool may explicitly opt out when executing
66 // it during planning is semantically invalid.
67 func (Policy) Decide(call Call) Decision {
68 if call.Safety != PlanSafetyUnsafe {
69 return Decision{}
70 }
71 name := strings.TrimSpace(call.Name)
72 return Decision{
73 Blocked: true,
74 Message: fmt.Sprintf("blocked: %q is not available during the planning workflow. Finish or exit Plan mode before calling it.", name),
75 }
76 }
77
77 lines GO