mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
Merge remote-tracking branch 'origin/main-v2' into fix/pr-8275-agent-role-settings
# Conflicts: # internal/agent/run_loop.go
This commit is contained in:
commit
ec2da98bda
2 files changed
+95
-12
No files matched your search
+12
-12
@@ -115,7 +115,7 @@ func (a *Agent) beginRunTurn(ctx context.Context, input string) (rawInput string
|
||||
// A fresh user turn starts from zeroed per-turn host state; the new turn's
|
||||
// values are computed below. Cross-turn state (checkpoint, scope, failure
|
||||
// budgets) lives directly on Agent and is reconciled field by field.
|
||||
a.perTurnState = perTurnState{turnInput: input}
|
||||
a.perTurnState = perTurnState{}
|
||||
a.resetStructuralRunGuards()
|
||||
scope, scoped := DeliveryExecutionScopeFromContext(ctx)
|
||||
preserveEvidence := a.preserveEvidenceOnce
|
||||
@@ -180,25 +180,25 @@ func (a *Agent) beginRunTurn(ctx context.Context, input string) (rawInput string
|
||||
// deadlocked read-only subagents. Without the override the raw input is
|
||||
// classified verbatim: stripping user-controllable markup here would let
|
||||
// input dressed up as host framing disarm the delivery gates.
|
||||
classifierInput := a.classifierTaskText
|
||||
a.turnInput = a.classifierTaskText
|
||||
if scoped && strings.TrimSpace(scope.TaskText) != "" {
|
||||
classifierInput = scope.TaskText
|
||||
} else if strings.TrimSpace(classifierInput) == "" {
|
||||
classifierInput = rawInput
|
||||
a.turnInput = scope.TaskText
|
||||
} else if strings.TrimSpace(a.turnInput) == "" {
|
||||
a.turnInput = rawInput
|
||||
}
|
||||
intent := taskintent.Classify(classifierInput)
|
||||
intent := taskintent.Classify(a.turnInput)
|
||||
a.deliveryTaskExpected = intent.NeedsEvidence()
|
||||
a.deliveryMutationExpected = intent == taskintent.Mutation && registryHasWriterTools(a.tools)
|
||||
a.deliveryPersistentExpected = taskintent.NeedsPersistentAction(classifierInput)
|
||||
a.recoveryTaskSummary = boundedRecoveryTaskSummary(classifierInput)
|
||||
a.deliveryPersistentExpected = taskintent.NeedsPersistentAction(a.turnInput)
|
||||
a.recoveryTaskSummary = boundedRecoveryTaskSummary(a.turnInput)
|
||||
// Freeze TaskPolicy for this turn from the session role setting. Subsequent
|
||||
// SetAgentPreset calls must not change this turn's route/review floor.
|
||||
if policy, ok := taskpolicy.FromContext(ctx); ok {
|
||||
a.turnPolicy = policy
|
||||
} else {
|
||||
a.turnPolicy = taskpolicy.Derive(taskpolicy.Input{
|
||||
Raw: classifierInput,
|
||||
Instruction: taskpolicy.StripQuotedConstraints(classifierInput),
|
||||
Raw: a.turnInput,
|
||||
Instruction: taskpolicy.StripQuotedConstraints(a.turnInput),
|
||||
Preset: agentpreset.AgentPreset(a.AgentPreset()),
|
||||
PlanMode: a.planMode.Load(),
|
||||
})
|
||||
@@ -234,7 +234,7 @@ func (a *Agent) beginRunTurn(ctx context.Context, input string) (rawInput string
|
||||
a.activeTurnCreatedAt.Store(userCreatedAt)
|
||||
rawContent := rawInput
|
||||
if rawContent == "" {
|
||||
rawContent = classifierInput
|
||||
rawContent = a.turnInput
|
||||
}
|
||||
a.session.Add(provider.Message{
|
||||
Role: provider.RoleUser, Content: input, RawContent: rawContent,
|
||||
@@ -597,7 +597,7 @@ func (a *Agent) handleFinalResponse(ctx context.Context, state *runLoopState, te
|
||||
if readiness.applies {
|
||||
event.RecordReadinessAudit(a.sink, readiness.audit(evidence.ReadinessAllowed, a.readinessRecovered))
|
||||
}
|
||||
a.emitTurnShadows(state.input)
|
||||
a.emitTurnShadows(a.turnInput)
|
||||
if !a.closeSteerIntakeIfIdle() {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -70,6 +70,89 @@ func TestRunPersistsRawUserInputSeparatelyFromProviderContext(t *testing.T) {
|
||||
if !strings.HasPrefix(legacy.Content, composed) || !strings.Contains(legacy.Content, "<execution-policy") {
|
||||
t.Fatalf("previous-release reader sees %q, want provider-visible composed prefix plus execution-policy", legacy.Content)
|
||||
}
|
||||
|
||||
receipt := a.CompletionReceipt()
|
||||
if receipt == nil {
|
||||
t.Fatal("completion receipt is nil")
|
||||
}
|
||||
if len(receipt.Gaps) != 2 {
|
||||
t.Fatalf("completion gaps = %+v, want the atomic requirement and mutation check", receipt.Gaps)
|
||||
}
|
||||
if got := receipt.Gaps[0].Detail; got != "r1: "+raw {
|
||||
t.Fatalf("atomic criterion = %q, want raw user input %q", got, raw)
|
||||
}
|
||||
if strings.Contains(receipt.Gaps[0].Detail, "capability-route") {
|
||||
t.Fatalf("completion receipt leaked transient provider context: %+v", receipt.Gaps)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransientCapabilityRouteCannotTurnConversationIntoDeliveryReceipt(t *testing.T) {
|
||||
prov := &userInputCaptureProvider{}
|
||||
a := New(prov, tool.NewRegistry(), NewSession("system"), Options{}, event.Discard)
|
||||
|
||||
const raw = "请解释这个项目目前的进度"
|
||||
const composed = `<capability-route version="1">
|
||||
Relevant capabilities for this turn:
|
||||
- skill:minimax-docx prefer: the skill trigger matches the user request
|
||||
Policy: prefer means use the skill for the required change
|
||||
</capability-route>
|
||||
|
||||
` + raw
|
||||
if err := a.Run(WithRawUserInput(context.Background(), raw), composed); err != nil {
|
||||
t.Fatalf("Run: %v", err)
|
||||
}
|
||||
|
||||
if a.CompletionReceipt() != nil {
|
||||
t.Fatalf("an advisory turn received a delivery receipt from transient routing: %+v", a.CompletionReceipt())
|
||||
}
|
||||
if len(prov.request.Messages) < 2 ||
|
||||
!strings.Contains(prov.request.Messages[1].Content, `<capability-route version="1">`) ||
|
||||
!strings.Contains(prov.request.Messages[1].Content, raw) {
|
||||
t.Fatalf("provider lost the capability route: %+v", prov.request.Messages)
|
||||
}
|
||||
if got := a.turnInput; got != raw {
|
||||
t.Fatalf("contract input = %q, want authenticated raw input %q", got, raw)
|
||||
}
|
||||
c := a.LiveContract()
|
||||
if c == nil || len(c.Requirements) != 0 || len(c.Checks) != 0 {
|
||||
t.Fatalf("transient route created delivery requirements: %+v", c)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompletionContractUsesGoalScopeTaskText(t *testing.T) {
|
||||
prov := &userInputCaptureProvider{}
|
||||
a := New(prov, tool.NewRegistry(), NewSession("system"), Options{}, event.Discard)
|
||||
ctx := WithRawUserInput(context.Background(), "Continue working.")
|
||||
ctx = WithDeliveryExecutionScope(ctx, DeliveryExecutionScope{ID: "goal-1", TaskText: "fix the parser"})
|
||||
|
||||
if err := a.Run(ctx, "<goal-context>continue</goal-context>"); err != nil {
|
||||
t.Fatalf("Run: %v", err)
|
||||
}
|
||||
assertAtomicCriterion(t, a, "fix the parser")
|
||||
}
|
||||
|
||||
func TestCompletionContractUsesPristineSubagentTaskText(t *testing.T) {
|
||||
prov := &userInputCaptureProvider{}
|
||||
a := New(prov, tool.NewRegistry(), NewSession("system"), Options{
|
||||
ClassifierTaskText: "fix the parser",
|
||||
}, event.Discard)
|
||||
const wrapped = "<workspace-context>private host framing</workspace-context>\n\nfix the parser"
|
||||
|
||||
if err := a.Run(context.Background(), wrapped); err != nil {
|
||||
t.Fatalf("Run: %v", err)
|
||||
}
|
||||
assertAtomicCriterion(t, a, "fix the parser")
|
||||
}
|
||||
|
||||
func assertAtomicCriterion(t *testing.T, a *Agent, want string) {
|
||||
t.Helper()
|
||||
receipt := a.CompletionReceipt()
|
||||
if receipt == nil || len(receipt.Gaps) == 0 {
|
||||
t.Fatalf("completion receipt = %+v, want atomic criterion %q", receipt, want)
|
||||
}
|
||||
if got := receipt.Gaps[0].Detail; got != "r1: "+want {
|
||||
t.Fatalf("atomic criterion = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubagentImageCandidatesAreCopiedAndIsolated(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user