mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
A fold leaves the model with a digest, and the host re-projected only the step ids of plan-seeded unfinished lists. A task list the model wrote itself (no ids), a list with every item complete, the files changed and the checks that passed all survived only as digest prose, which a weaker model reads as work not yet done and repeats. While a fold is installed the request now ends with one derived "Host progress record": the canonical task list with statuses when no todo_write is left in view, the files changed in the folded prefix, and the verification commands whose latest outcome was a pass (marked when a file changed after them). It is derived from tool receipts, bounded (30 files, 15 checks, with the omitted count), memoised on the covered-prefix fingerprint, and ends with the fold. Sessions that never folded carry nothing extra.
100 lines
3.7 KiB
Go
100 lines
3.7 KiB
Go
package agent
|
|
|
|
// Re-projection of the canonical task list's identities: a fold can take the
|
|
// step ids out of view while the host still holds them, and complete_step goes
|
|
// on asking for one. Derived per request, stored nowhere.
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
|
|
"reasonix/internal/contract/provider"
|
|
"reasonix/internal/safety/evidence"
|
|
)
|
|
|
|
// todoIdentityNote renders the ids a sign-off must cite. It states whose list
|
|
// this is: an unattributed task list reads as something the model itself sent.
|
|
func todoIdentityNote(todos []evidence.TodoItem) string {
|
|
var b strings.Builder
|
|
b.WriteString("Host task state. This list is the host's, not a message you sent; cite these step ids in complete_step:")
|
|
for i, t := range todos {
|
|
b.WriteString("\n - " + todoStateLine(i+1, t))
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
// todoStateLine is the single rendering of one item, shared by the note and the
|
|
// freshness check so the two cannot diverge.
|
|
func todoStateLine(index int, t evidence.TodoItem) string {
|
|
return fmt.Sprintf("%s (%s)", evidence.TodoCitation(t.StepID, index, t.Content), t.Status)
|
|
}
|
|
|
|
// withTodoIdentityTail appends the host's task state when the request cannot
|
|
// already read it. Owed is recomputed per request from canonical state, never
|
|
// from a record of what an earlier request carried. A list with every item
|
|
// complete owes nothing: the tail exists so a sign-off can cite an id, and that
|
|
// plan has none left — carried into the next task it reads as work outstanding.
|
|
func (a *Agent) withTodoIdentityTail(visible []provider.Message) []provider.Message {
|
|
todos := a.CanonicalTodoState()
|
|
if !todoIdentityOwed(visible, todos) {
|
|
return visible
|
|
}
|
|
return append(visible, provider.Message{Role: provider.RoleUser, Content: todoIdentityNote(todos), Derived: true})
|
|
}
|
|
|
|
func todoIdentityOwed(visible []provider.Message, todos []evidence.TodoItem) bool {
|
|
return len(evidence.TodoStepIDs(todos)) > 0 && len(evidence.IncompleteTodos(todos)) > 0 && !todoStateVisible(visible, todos)
|
|
}
|
|
|
|
// withFoldProgressTail appends the host's record of finished work once a fold
|
|
// is installed, and nothing before one. The task list rides it only when no
|
|
// todo_write is left in view and the identity note is not already carrying it;
|
|
// the record lasts as long as the fold, so a rewind or a new session ends it.
|
|
func (a *Agent) withFoldProgressTail(visible []provider.Message, p *foldProgress) []provider.Message {
|
|
if p == nil {
|
|
return visible
|
|
}
|
|
var todos []evidence.TodoItem
|
|
if listed := a.CanonicalTodoState(); !todoIdentityOwed(visible, listed) && !todoWriteVisible(visible) {
|
|
todos = listed
|
|
}
|
|
note := foldProgressNote(todos, *p)
|
|
if note == "" {
|
|
return visible
|
|
}
|
|
return append(visible, provider.Message{Role: provider.RoleUser, Content: note, Derived: true})
|
|
}
|
|
|
|
func todoWriteVisible(msgs []provider.Message) bool {
|
|
return slices.ContainsFunc(msgs, func(m provider.Message) bool {
|
|
return slices.ContainsFunc(m.ToolCalls, func(tc provider.ToolCall) bool { return tc.Name == "todo_write" })
|
|
})
|
|
}
|
|
|
|
// todoStateVisible reports whether the view already carries the host's current
|
|
// reading of every item. Ids alone do not answer it: they persist in the model's
|
|
// own todo_write after complete_step has moved the status under them.
|
|
func todoStateVisible(msgs []provider.Message, todos []evidence.TodoItem) bool {
|
|
for i, t := range todos {
|
|
if !messagesMention(msgs, todoStateLine(i+1, t)) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func messagesMention(msgs []provider.Message, needle string) bool {
|
|
for _, msg := range slices.Backward(msgs) {
|
|
if strings.Contains(msg.Content, needle) {
|
|
return true
|
|
}
|
|
for _, call := range msg.ToolCalls {
|
|
if strings.Contains(call.Arguments, needle) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|