返回 DeepSeek-Reasonix
blocked.go
根目录 / internal / browser / blocked.go
1 package browser
2
3 import (
4 "errors"
5 "fmt"
6
7 "reasonix/internal/tool"
8 )
9
10 const (
11 noBrowserText = "blocked: no browser is attached to this session, so browser tools are unavailable; do not retry."
12 noGrantText = "blocked: this task holds no browser grant. The browser is unavailable until the host grants access; do not retry."
13 staleText = "blocked: stale reference - the page changed since that snapshot. Call browser_snapshot again and act with its documentToken and a fresh operationId."
14 takenOverText = "blocked: the user took over this tab, which invalidated every earlier reference. Wait for the user to finish, then call browser_snapshot again before acting."
15 )
16
17 // translate maps executor sentinels onto tool outcomes: refusals become
18 // blocked cards (never retried), a lost receipt becomes an error that
19 // forbids a retry, and anything else passes through unchanged.
20 func translate(err error, what string) error {
21 switch {
22 case err == nil:
23 return nil
24 case errors.Is(err, ErrStaleReference):
25 return tool.Blocked(staleText)
26 case errors.Is(err, ErrTakenOver):
27 return tool.Blocked(takenOverText)
28 case errors.Is(err, ErrNoGrant):
29 return tool.Blocked(noGrantText)
30 case errors.Is(err, ErrUnknownOutcome):
31 return unknownOutcome(what)
32 }
33 return err
34 }
35
36 func unknownOutcome(what string) error {
37 return fmt.Errorf("outcome unknown: the browser did not confirm whether %s ran. It may or may not have taken effect, so it must not be retried with the same or a new operationId. Call browser_snapshot to observe the page before deciding what to do next.", what)
38 }
39
40 func notExecuted(what, reason string) error {
41 if reason == "" {
42 reason = "no reason reported"
43 }
44 return fmt.Errorf("not_executed: %s (%s). Take a new browser_snapshot and retry with its documentToken and a fresh operationId.", what, reason)
45 }
46
46 lines GO