返回 DeepSeek-Reasonix
execution_engine.go
根目录 / internal / agent / execution_engine.go
1 package agent
2
3 import (
4 "context"
5 "encoding/json"
6
7 "reasonix/internal/evidence"
8 "reasonix/internal/runtimepolicy"
9 "reasonix/internal/tool"
10 )
11
12 // withInheritedHostConstraints re-applies the spawning turn's host constraints
13 // to a background job context. Jobs run on a root context, so without this a
14 // child would re-derive its constraints from the model-authored task prompt.
15 func withInheritedHostConstraints(parent, job context.Context) context.Context {
16 if c, ok := runtimepolicy.FromContext(parent); ok {
17 job = runtimepolicy.WithContext(job, c)
18 }
19 if in, ok := runtimepolicy.InheritedFromContext(parent); ok {
20 job = runtimepolicy.WithInherited(job, in)
21 }
22 return job
23 }
24
25 func mergeInheritedConstraints(child, parent runtimepolicy.Constraints) runtimepolicy.Constraints {
26 if parent.ForbidMutation {
27 child.ForbidMutation = true
28 }
29 if parent.ForbidTests {
30 child.ForbidTests = true
31 }
32 if parent.ForbidExternal {
33 child.ForbidExternal = true
34 }
35 if parent.PlanModeReadOnly {
36 child.PlanModeReadOnly = true
37 child.ForbidMutation = true
38 }
39 if len(parent.AllowedChecks) > 0 && len(child.AllowedChecks) == 0 {
40 child.AllowedChecks = append([]string(nil), parent.AllowedChecks...)
41 }
42 if len(parent.RebuildPaths) > 0 && len(child.RebuildPaths) == 0 {
43 child.RebuildPaths = append([]string(nil), parent.RebuildPaths...)
44 }
45 return child
46 }
47
48 func (a *Agent) pipelineDecision(plan *toolCallPlan) runtimepolicy.GuardDecision {
49 if a == nil || plan == nil || a.turn.engine == nil {
50 return runtimepolicy.GuardDecision{}
51 }
52 profile := evidence.ClassifyEffect(evidence.EffectInput{
53 ToolName: plan.evidenceName,
54 Args: plan.evidenceArgs,
55 StaticReadOnly: plan.readOnly,
56 Hint: effectHintOf(plan.execTool, plan.execArgs),
57 ActualPaths: evidence.ToolCallPaths(plan.evidenceArgs),
58 WorkspaceRoot: a.writeWorkspaceRoot,
59 })
60 plan.profile = profile
61 plan.effects = profile.ToolEffects()
62 return a.turn.engine.BeforeTool(runtimepolicy.CallContext{
63 ToolName: plan.evidenceName,
64 Args: plan.evidenceArgs,
65 Profile: profile,
66 PlanReadOnly: a.planMode.Load() || a.turn.constraints.PlanModeReadOnly,
67 Interactive: a.hasInteractiveAsk(),
68 Verification: tool.IsShellToolName(plan.evidenceName) && evidence.IsVerificationCommand(bashCommandFromArgs(plan.evidenceArgs)),
69 TestsForbidden: a.turn.constraints.ForbidTests,
70 WorkspaceRoot: a.writeWorkspaceRoot,
71 })
72 }
73
74 func effectHintOf(t tool.Tool, args json.RawMessage) evidence.CallHint {
75 if t == nil {
76 return evidence.CallHint{}
77 }
78 hint := evidence.CallHint{Present: true, ReadOnly: t.ReadOnly()}
79 if d, ok := t.(interface{ MCPDestructiveHint() bool }); ok {
80 hint.Destructive = d.MCPDestructiveHint()
81 }
82 if p, ok := t.(tool.EffectHintProvider); ok {
83 h := p.EffectHint(args)
84 hint.Known = h.Known
85 hint.ReadOnly = hint.ReadOnly || h.ReadOnly
86 hint.Destructive = hint.Destructive || h.Destructive
87 hint.Privileged = h.Privileged
88 hint.UsesNetwork = h.UsesNetwork
89 hint.ExecutesCode = h.ExecutesCode
90 hint.Targets = append([]string(nil), h.Targets...)
91 }
92 return hint
93 }
94
95 func (a *Agent) hasInteractiveAsk() bool {
96 if a == nil || a.svc.gate == nil {
97 return false
98 }
99 _, ok := a.svc.gate.(interface {
100 Ask(any) (bool, error)
101 })
102 return ok
103 }
104
104 lines GO