fix(worker): 写回计数按事实/资产/漏洞分开统计
原先 record_fact/insert_assets/report_finding 共用一个 wrote 计数器,
日志却统一打印成"写回 N 条事实",把资产、漏洞也算进"事实"里,容易误导
(如枚举意图插入 25 个资产 + 1 条 fact 会显示"写回 26 条事实")。
改为 WriteCounts{Facts,Assets,Findings} 分类计数,日志打印
"写回 事实1 资产25 漏洞0",Total() 保留"是否落库任何东西"的判定。
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
1 parent
2c3ca4b194
commit
abc551cc76
4 files changed
+36
-15
No files matched your search
+26
-6
@@ -58,7 +58,7 @@ type ToolSet struct {
|
||||
ownerNode int64
|
||||
GoalMet bool
|
||||
Reason string
|
||||
wrote int
|
||||
writes WriteCounts
|
||||
// killWork, if set, terminates a running work by intent id (engine callback,
|
||||
// wired by the planner). nil = the kill_work tool reports unavailable.
|
||||
killWork func(intentID int64) error
|
||||
@@ -86,9 +86,29 @@ type EnrichTrigger interface {
|
||||
ProbeSite(id int64, url string)
|
||||
}
|
||||
|
||||
// Wrote reports how many facts this run wrote back (so the engine can tell
|
||||
// "explored but persisted nothing" apart from a completed intent).
|
||||
func (t *ToolSet) Wrote() int { return t.wrote }
|
||||
// WriteCounts breaks down what a worker persisted this run, by node kind, so the
|
||||
// engine can log an accurate "wrote back" summary instead of lumping assets and
|
||||
// findings under "facts" (record_fact → Facts, insert_assets → Assets,
|
||||
// report_finding → Findings; each element of a batch counts once).
|
||||
type WriteCounts struct {
|
||||
Facts int
|
||||
Assets int
|
||||
Findings int
|
||||
}
|
||||
|
||||
// Total is every node persisted this run, regardless of kind — the
|
||||
// "explored but persisted nothing" signal (Total == 0).
|
||||
func (w WriteCounts) Total() int { return w.Facts + w.Assets + w.Findings }
|
||||
|
||||
// String renders the per-kind breakdown for logs, e.g. "事实1 资产25 漏洞0".
|
||||
func (w WriteCounts) String() string {
|
||||
return fmt.Sprintf("事实%d 资产%d 漏洞%d", w.Facts, w.Assets, w.Findings)
|
||||
}
|
||||
|
||||
// Writes reports what this run wrote back, split by node kind (so the engine can
|
||||
// tell "explored but persisted nothing" apart from a completed intent, and log an
|
||||
// honest breakdown instead of calling assets/findings "facts").
|
||||
func (t *ToolSet) Writes() WriteCounts { return t.writes }
|
||||
|
||||
func NewToolSet(ts *db.ExplorationStore, worker string) *ToolSet {
|
||||
return &ToolSet{ts: ts, worker: worker}
|
||||
@@ -594,7 +614,7 @@ func (t *ToolSet) addFinding() actool.CoreTool {
|
||||
// conversation context: no exploration store available, cannot record finding
|
||||
return actool.Errorf("report_finding 需要任务上下文(exploration store 未初始化)"), nil
|
||||
}
|
||||
t.wrote++
|
||||
t.writes.Findings++
|
||||
return actool.Text(fmt.Sprintf("finding recorded: %d", id)), nil
|
||||
})
|
||||
}
|
||||
@@ -642,7 +662,7 @@ func (t *ToolSet) recordOneFact(it factItem, defaultIntent int64) (int64, error)
|
||||
if intent > 0 {
|
||||
_ = t.ts.Link(intent, db.RelYields, id) // chain: intent -> fact
|
||||
}
|
||||
t.wrote++
|
||||
t.writes.Facts++
|
||||
return id, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@ func (t *ToolSet) insertAssets() actool.CoreTool {
|
||||
continue
|
||||
}
|
||||
results = append(results, result{Index: i, ID: id, Type: typ})
|
||||
t.wrote++
|
||||
t.writes.Assets++
|
||||
t.anchorOwner(id)
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -193,9 +193,10 @@ func renderWorkerGraphOverview(data map[string]any) string {
|
||||
// Execute runs one intent. hooks (the per-task Guard) gates every tool call; may
|
||||
// be nil. emit, if non-nil, receives one ActivityRecord per execution step.
|
||||
// Returns the terminal reason (so the engine can distinguish completed vs
|
||||
// max_turns) and how many facts were written back (so an intent that explored but
|
||||
// persisted nothing isn't mistaken for done).
|
||||
func (w *Worker) Execute(ctx context.Context, name string, taskID int64, as *db.AssetStore, ts *db.ExplorationStore, intent *db.Node, hooks harness.HookRunner, emit func(db.Activity), enr EnrichTrigger) (harness.TerminalReason, int, error) {
|
||||
// max_turns) and a per-kind breakdown of what was written back (so an intent that
|
||||
// explored but persisted nothing isn't mistaken for done, and the engine can log
|
||||
// facts/assets/findings separately instead of lumping them under "facts").
|
||||
func (w *Worker) Execute(ctx context.Context, name string, taskID int64, as *db.AssetStore, ts *db.ExplorationStore, intent *db.Node, hooks harness.HookRunner, emit func(db.Activity), enr EnrichTrigger) (harness.TerminalReason, WriteCounts, error) {
|
||||
tsx := NewToolSet(ts, name)
|
||||
tsx.SetTaskID(taskID)
|
||||
if as != nil {
|
||||
@@ -298,5 +299,5 @@ func (w *Worker) Execute(ctx context.Context, name string, taskID int64, as *db.
|
||||
defer runCancel()
|
||||
}
|
||||
_, reason, err := captureRunSession(runCtx, s, input, emitWrap)
|
||||
return reason, tsx.Wrote(), err
|
||||
return reason, tsx.Writes(), err
|
||||
}
|
||||
+4
-4
@@ -532,7 +532,7 @@ func (e *Engine) workerLoop(ctx context.Context, t *Task, name string) {
|
||||
// 不要误标 blocked。此时 worker 通常已在 settlement 阶段把结果写回。
|
||||
if ectx.Err() != nil && e.isSettling(t.ID) {
|
||||
_ = t.Store.SetIntentState(intent.ID, "exhausted")
|
||||
log.Printf("[worker %s] task %s 意图 #%d 因任务超时收尾结束(exhausted),写回 %d 条", name, t.ID, intent.ID, wrote)
|
||||
log.Printf("[worker %s] task %s 意图 #%d 因任务超时收尾结束(exhausted),写回 %s", name, t.ID, intent.ID, wrote)
|
||||
e.touch(t.ID)
|
||||
continue
|
||||
}
|
||||
@@ -563,13 +563,13 @@ func (e *Engine) workerLoop(ctx context.Context, t *Task, name string) {
|
||||
state = "blocked"
|
||||
case reason == harness.ReasonMaxTurns:
|
||||
state = "exhausted"
|
||||
log.Printf("[worker %s] intent %d 撞步数上限(exhausted),本次写回事实 %d 条", name, intent.ID, wrote)
|
||||
log.Printf("[worker %s] intent %d 撞步数上限(exhausted),本次写回 %s", name, intent.ID, wrote)
|
||||
case reason == harness.ReasonTimeout:
|
||||
state = "exhausted"
|
||||
log.Printf("[worker %s] intent %d 运行超时(exhausted),收尾后写回事实 %d 条", name, intent.ID, wrote)
|
||||
log.Printf("[worker %s] intent %d 运行超时(exhausted),收尾后写回 %s", name, intent.ID, wrote)
|
||||
}
|
||||
_ = t.Store.SetIntentState(intent.ID, state)
|
||||
log.Printf("[worker %s] task %s 意图 #%d 结束: %s (写回 %d 条事实)", name, t.ID, intent.ID, state, wrote)
|
||||
log.Printf("[worker %s] task %s 意图 #%d 结束: %s (写回 %s)", name, t.ID, intent.ID, state, wrote)
|
||||
e.touch(t.ID)
|
||||
t.NotifyDone(intent.ID) // results changed the graph -> wake the planner (with the just-finished intent id)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user