mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-13 11:40:53 +08:00
Three orchestration mechanisms from the Q00/ouroboros evaluation (#99): - Goal ambiguity gate at task creation: a goal must name a target (URL, domain, IPv4, localhost:port or absolute path) and reach a length floor, else the API returns 400 before any token is spent. Deliberately target-less goals opt out with the literal marker [targetless]. Guards against the live failure where a goal naming no target sent every worker to an unrelated asset. - Consecutive-failure escalation on the task LLM chain: quota exhaustion already advances the chain; now 3 consecutive non-quota call failures on the same chain profile advance it too, with the true reason recorded. Escalation-only by design (no auto-downgrade: mid-task model swaps risk behavior drift; the operator keeps the manual chain reset). - Stagnation surfacing in the planner overview: finished intents are fingerprinted (case-folded, digits collapsed); a direction dispatched 3+ times with zero findings since its first attempt is flagged in a self-describing stagnation_warning payload that instructs the planner to diversify instead of grinding. Absent when nothing stagnates. Closes #99
40 lines
1.4 KiB
Go
40 lines
1.4 KiB
Go
package agent
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/Autumn-27/artex/db"
|
|
)
|
|
|
|
func nodeWithSummary(id int64, summary string) *db.Node {
|
|
payload, _ := json.Marshal(map[string]any{"summary": summary})
|
|
return &db.Node{ID: id, Kind: db.KindIntent, State: "done", Payload: payload}
|
|
}
|
|
|
|
func TestDetectStagnation(t *testing.T) {
|
|
done := []*db.Node{
|
|
nodeWithSummary(10, "Enumerate endpoints on https://target.example.com/api/v2"),
|
|
nodeWithSummary(22, "Enumerate endpoints on https://target.example.com/api/v3"),
|
|
nodeWithSummary(35, "enumerate endpoints on https://target.example.com/api/v9"),
|
|
nodeWithSummary(40, "Review authentication flow for token replay"),
|
|
}
|
|
if got := detectStagnation(done, nil); len(got) != 1 {
|
|
t.Fatalf("expected 1 stagnating direction, got %d: %+v", len(got), got)
|
|
} else if got[0]["repeats"] != 3 {
|
|
t.Fatalf("repeats=%v want 3", got[0]["repeats"])
|
|
}
|
|
|
|
// a finding produced after the first repeat disarms the direction
|
|
findingPayload, _ := json.Marshal(map[string]any{"summary": "IDOR found"})
|
|
findings := []*db.Node{{ID: 25, Kind: db.KindFinding, Payload: findingPayload}}
|
|
if got := detectStagnation(done, findings); len(got) != 0 {
|
|
t.Fatalf("expected no stagnation once a finding exists, got %+v", got)
|
|
}
|
|
|
|
// below the repeat threshold: nothing
|
|
if got := detectStagnation(done[:2], nil); len(got) != 0 {
|
|
t.Fatalf("expected no stagnation below threshold, got %+v", got)
|
|
}
|
|
}
|