返回 DeepSeek-Reasonix
complete_subtask.go
根目录 / internal / agent / complete_subtask.go
1 package agent
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7
8 "reasonix/internal/evidence"
9 "reasonix/internal/tool"
10 )
11
12 // CompleteSubtaskTool optionally records the child's own completion report.
13 // It is never registered on the parent agent's tool surface.
14 type CompleteSubtaskTool struct{}
15
16 func NewCompleteSubtaskTool() *CompleteSubtaskTool { return &CompleteSubtaskTool{} }
17
18 func (*CompleteSubtaskTool) Name() string { return tool.HostCompleteSubtask }
19
20 func (*CompleteSubtaskTool) Description() string {
21 return "Optionally report this delegated sub-task's outcome to the parent. status is complete, partial, blocked, or failed; summary states what is now true; acceptance_criteria lists your assessment and supporting information; unresolved lists what remains. This is your report; the host displays actual execution facts separately. A final prose answer is also sufficient."
22 }
23
24 // ReadOnly is true: submitting a report changes no workspace state. It is the
25 // claim itself, not a mutation.
26 func (*CompleteSubtaskTool) ReadOnly() bool { return true }
27
28 func (*CompleteSubtaskTool) Schema() json.RawMessage {
29 // Fixed schema — sub-agent registries only, so it never enters the parent
30 // prefix.
31 return json.RawMessage(`{
32 "type":"object",
33 "properties":{
34 "status":{"type":"string","description":"Your assessment: complete | partial | blocked | failed."},
35 "summary":{"type":"string","description":"What is now true as a result of this sub-task."},
36 "acceptance_criteria":{
37 "type":"array",
38 "description":"Your assessment of each condition and its supporting information.",
39 "items":{
40 "type":"object",
41 "properties":{
42 "id":{"type":"string","description":"Short stable id, e.g. AC1."},
43 "status":{"type":"string","description":"satisfied | unsatisfied"},
44 "evidence":{
45 "type":"array",
46 "items":{
47 "type":"object",
48 "properties":{
49 "kind":{"type":"string","enum":["verification","review","diff","files","manual"],"description":"verification = a command was run (command REQUIRED); review = a review completed; diff = a code change (paths REQUIRED); files = files created/edited/inspected (paths REQUIRED); manual = a manual check, which the host cannot back on its own."},
50 "summary":{"type":"string","description":"The evidence itself."},
51 "command":{"type":"string","description":"REQUIRED for verification: the command as it actually ran."},
52 "paths":{"type":"array","items":{"type":"string"},"description":"REQUIRED for diff/files: the files this evidence refers to."}
53 },
54 "required":["kind","summary"]
55 }
56 }
57 },
58 "required":["id","status"]
59 }
60 },
61 "unresolved":{"type":"array","items":{"type":"string"},"description":"What remains undone, unverified, or blocked. Put anything you assumed rather than checked here."}
62 },
63 "required":["status","summary"]
64 }`)
65 }
66
67 func (*CompleteSubtaskTool) Execute(ctx context.Context, args json.RawMessage) (string, error) {
68 report, err := evidence.ParseCompletionReport(args)
69 if err != nil {
70 return "", err
71 }
72 return fmt.Sprintf("complete_subtask recorded as model report: status=%s criteria=%d unresolved=%d",
73 report.Status, len(report.Criteria), len(report.Unresolved)), nil
74 }
75
76 // AttachCompleteSubtaskTool adds complete_subtask to a sub-agent registry.
77 // Parent registries never receive it.
78 func AttachCompleteSubtaskTool(reg *tool.Registry) {
79 if reg == nil {
80 return
81 }
82 reg.Add(NewCompleteSubtaskTool())
83 }
84
85 // CompletionReport returns the model's report without host adjudication.
86 func (a *Agent) CompletionReport() (evidence.CompletionReport, bool) {
87 if a == nil || a.task.ledger == nil {
88 return evidence.CompletionReport{}, false
89 }
90 return a.task.ledger.LatestCompletionReport()
91 }
92
93 // completeSubtaskContract is appended to a sub-agent's task prompt when the
94 // host offers a typed completion report as an alternative to prose.
95 const completeSubtaskContract = `<completion-contract>
96 Finish with a clear final answer, or optionally use complete_subtask to provide a
97 structured report. State what you completed and what remains uncertain or undone.
98 Your completion assessment is shown separately from host-recorded execution facts.
99 </completion-contract>`
100
100 lines GO