返回 DeepSeek-Reasonix
goal_run_boundary.go
根目录 / internal / agent / goal_run_boundary.go
1 package agent
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7
8 "reasonix/internal/provider"
9 )
10
11 // maxStepsPause is a resumable stop after a positive model-round budget.
12 type maxStepsPause struct {
13 steps int
14 key string
15 }
16
17 func (e *maxStepsPause) Error() string {
18 return fmt.Sprintf("paused after %d tool-call rounds (%s) — the work so far is saved; send another message to continue, or set %s higher or to 0 for no limit", e.steps, e.key, e.key)
19 }
20
21 func isToolLoopPause(err error) bool {
22 var maxPause *maxStepsPause
23 var budgetPause *taskBudgetPause
24 return errors.As(err, &maxPause) || errors.As(err, &budgetPause)
25 }
26
27 // HostProgressSignatures exposes successful evidence identities to the Goal FSM.
28 func (a *Agent) HostProgressSignatures() []string {
29 if a == nil || a.task.ledger == nil {
30 return nil
31 }
32 return a.task.ledger.SuccessfulProgressSignaturesSince(0)
33 }
34
35 // resetTurnEvidence starts a fresh execution-fact projection for a new task
36 // scope. Facts remain useful for display and Goal accounting but do not gate
37 // later tools or model completion.
38 func (a *Agent) resetTurnEvidence() {
39 a.task.restartLedger()
40 }
41
42 func (a *Agent) stopUnexecutedBoundaryCalls(ctx context.Context, state *turnRuntime, calls []provider.ToolCall, usage *provider.Usage) (error, bool) {
43 switch {
44 case state.graceRound && !a.allowsBoundaryTurnFinalizer(ctx, state, calls):
45 if err := a.pairUnexecutedGraceCalls(ctx, calls, "blocked: the tool-call round budget is exhausted; no more tools will run in this turn"); err != nil {
46 return err, true
47 }
48 return a.gracePause(state), true
49 default:
50 return nil, false
51 }
52 }
53
53 lines GO