feat: update config, session manager, tools dag and subagent

This commit is contained in:
ZanzyTHEbar 2026-03-04 18:44:20 +00:00
parent 45b525b832
commit 8b9fd30cd7
4 changed files with 67 additions and 1 deletions

View file

@ -144,6 +144,14 @@ type ContinuityRetentionConfig struct {
FailureKeepMessages int `json:"failure_keep_messages" env:"DRAGONSCALE_AGENTS_DEFAULTS_CONTINUITY_RETENTION_FAILURE_KEEP_MESSAGES"` FailureKeepMessages int `json:"failure_keep_messages" env:"DRAGONSCALE_AGENTS_DEFAULTS_CONTINUITY_RETENTION_FAILURE_KEEP_MESSAGES"`
} }
// CompactionConfig controls the dual-threshold compaction control loop (LCM ADR-002).
type CompactionConfig struct {
// SoftThresholdPct triggers async background compaction (default 70).
SoftThresholdPct int `json:"soft_threshold_pct" env:"DRAGONSCALE_AGENTS_DEFAULTS_COMPACTION_SOFT_THRESHOLD_PCT"`
// HardThresholdPct triggers synchronous blocking compaction (default 90).
HardThresholdPct int `json:"hard_threshold_pct" env:"DRAGONSCALE_AGENTS_DEFAULTS_COMPACTION_HARD_THRESHOLD_PCT"`
}
type AgentDefaults struct { type AgentDefaults struct {
// Sandbox is the directory for agent file operations (tools sandbox). // Sandbox is the directory for agent file operations (tools sandbox).
// Defaults to $XDG_DATA_HOME/dragonscale/sandbox when empty. // Defaults to $XDG_DATA_HOME/dragonscale/sandbox when empty.
@ -155,6 +163,7 @@ type AgentDefaults struct {
Temperature float64 `json:"temperature" env:"DRAGONSCALE_AGENTS_DEFAULTS_TEMPERATURE"` Temperature float64 `json:"temperature" env:"DRAGONSCALE_AGENTS_DEFAULTS_TEMPERATURE"`
MaxToolIterations int `json:"max_tool_iterations" env:"DRAGONSCALE_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"` MaxToolIterations int `json:"max_tool_iterations" env:"DRAGONSCALE_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"`
ContinuityRetention ContinuityRetentionConfig `json:"continuity_retention"` ContinuityRetention ContinuityRetentionConfig `json:"continuity_retention"`
Compaction CompactionConfig `json:"compaction"`
// Deprecated: Use Sandbox instead. Kept for backward compatibility during migration. // Deprecated: Use Sandbox instead. Kept for backward compatibility during migration.
Workspace string `json:"workspace,omitempty" env:"DRAGONSCALE_AGENTS_DEFAULTS_WORKSPACE"` Workspace string `json:"workspace,omitempty" env:"DRAGONSCALE_AGENTS_DEFAULTS_WORKSPACE"`
@ -373,6 +382,10 @@ func DefaultConfig() *Config {
TargetContextRatio: 0.10, TargetContextRatio: 0.10,
FailureKeepMessages: 10, FailureKeepMessages: 10,
}, },
Compaction: CompactionConfig{
SoftThresholdPct: 70,
HardThresholdPct: 90,
},
}, },
}, },
Channels: ChannelsConfig{ Channels: ChannelsConfig{

View file

@ -402,6 +402,27 @@ func (sm *SessionManager) persistMessageToDelegate(sessionKey string, msg messag
map[string]interface{}{"session": sessionKey, "error": err.Error()}) map[string]interface{}{"session": sessionKey, "error": err.Error()})
return return
} }
// Dual-write: persist verbatim copy to immutable store (LCM ADR-001).
immutableWriter, ok := sm.delegate.(interface {
InsertImmutableMessage(ctx context.Context, msg *memory.ImmutableMessage) error
})
if ok {
imMsg := &memory.ImmutableMessage{
ID: ids.New(),
SessionKey: sessionKey,
Role: msg.Role,
Content: msg.Content,
ToolCallID: msg.ToolCallID,
ToolCalls: toolCallsJSON(msg),
TokenEstimate: estimateTokensSimple(msg.Content),
}
if err := immutableWriter.InsertImmutableMessage(ctx, imMsg); err != nil {
logger.WarnCF("session", "Failed to persist immutable message",
map[string]interface{}{"session": sessionKey, "error": err.Error()})
}
}
priorPtr, _ := sm.loadProjectionPointer(ctx, sessionKey) priorPtr, _ := sm.loadProjectionPointer(ctx, sessionKey)
newPtr := advancePointer(priorPtr, item.ID, now) newPtr := advancePointer(priorPtr, item.ID, now)
if err := sm.persistProjectionPointer(ctx, sessionKey, newPtr); err != nil { if err := sm.persistProjectionPointer(ctx, sessionKey, newPtr); err != nil {
@ -729,3 +750,18 @@ func (sm *SessionManager) SetHistory(key string, history []messages.Message) {
session.Updated = time.Now() session.Updated = time.Now()
} }
} }
func toolCallsJSON(msg messages.Message) string {
if len(msg.ToolCalls) == 0 {
return ""
}
b, err := jsonv2.Marshal(msg.ToolCalls)
if err != nil {
return ""
}
return string(b)
}
func estimateTokensSimple(content string) int {
return (len(content) + 3) / 4
}

View file

@ -29,7 +29,7 @@ type DAGToolDeps struct {
SessionFn func() string // returns current session key SessionFn func() string // returns current session key
} }
func recallRowToItem(row memsqlc.RecallItem) *memory.RecallItem { func recallRowToItem(row memsqlc.ListSessionMessagesPagedRow) *memory.RecallItem {
return &memory.RecallItem{ return &memory.RecallItem{
ID: row.ID, ID: row.ID,
AgentID: row.AgentID, AgentID: row.AgentID,

View file

@ -3,6 +3,7 @@ package tools
import ( import (
"context" "context"
"fmt" "fmt"
"log/slog"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -186,6 +187,14 @@ func (sm *SubagentManager) Spawn(ctx context.Context, task, label, delegatedScop
return "", fmt.Errorf("nested delegation requires delegated_scope and kept_work") return "", fmt.Errorf("nested delegation requires delegated_scope and kept_work")
} }
} }
if keptWork != "" {
slog.Debug("delegation scope-reduction",
"parent_depth", parentDepth,
"child_depth", childDepth,
"kept_work", keptWork,
"delegated_scope", delegatedScope,
)
}
if sm.runLoop == nil { if sm.runLoop == nil {
sm.mu.Unlock() sm.mu.Unlock()
return "", ErrRunLoopNotConfigured return "", ErrRunLoopNotConfigured
@ -461,6 +470,14 @@ func (t *SubagentTool) Execute(ctx context.Context, args map[string]interface{})
return ErrorResult("nested delegation requires delegated_scope and kept_work") return ErrorResult("nested delegation requires delegated_scope and kept_work")
} }
} }
if keptWork != "" {
slog.Debug("delegation scope-reduction",
"parent_depth", parentDepth,
"child_depth", childDepth,
"kept_work", keptWork,
"delegated_scope", delegatedScope,
)
}
systemPrompt := "You are a subagent operating with main-loop control flow. Execute actions via tools, call discovered tools directly, and provide a clear concise result." systemPrompt := "You are a subagent operating with main-loop control flow. Execute actions via tools, call discovered tools directly, and provide a clear concise result."