agent/toolsrv: replace classifier system with ToolMeta map
The entire classifier indirection (interfaces, type assertions, RPC methods for classification, closure wrappers in BuildRuntime) is replaced by a simple map[string]ToolInfo on Runtime. The .meta file is read once into ToolInfo. The loop reads fields directly: rt.ToolMeta[name].ReadOnly (was: rt.CanParallelize(name)) rt.ToolMeta[name].Tier (was: rt.MemoryTier(name, args)) rt.ToolMeta[name].OutputFormat (was: rt.OutputFormat(name)) rt.ToolMeta[name].ResetsCounter (was: rt.ResetsCounter(name)) Removed: ParallelClassifier, MemoryTierClassifier, OutputFormatClassifier interfaces, toolClassifier type, and all closure-wrapping in BuildRuntime. The RPC methods on Server/Conn stay (used by ollie-remote) but the agent no longer routes through them.
This commit is contained in:
parent
38b35f1ba5
commit
b6694d409a
|
|
@ -67,51 +67,11 @@ func BuildRuntime(cfg *AgentConfig, srv toolsrv.Runner, cwd string, env []string
|
|||
return text, blocks, nil
|
||||
}
|
||||
|
||||
var classify toolClassifier
|
||||
if pc, ok := srv.(toolsrv.ParallelClassifier); ok {
|
||||
classify = pc.CanParallelize
|
||||
}
|
||||
|
||||
// Capture output formats from the same tool listing used to build the
|
||||
// backend tool definitions. Remote runners expose ToolInfo through
|
||||
// ListTools, but do not necessarily implement OutputFormatClassifier.
|
||||
outputFormats := make(map[string]string, len(allToolInfos))
|
||||
// Build ToolMeta lookup from the tool listing — single source of truth
|
||||
// for all per-tool metadata (tier, readOnly, outputFormat, resetsCounter).
|
||||
toolMeta := make(map[string]toolsrv.ToolInfo, len(allToolInfos))
|
||||
for _, ti := range allToolInfos {
|
||||
outputFormats[ti.Name] = ti.OutputFormat
|
||||
}
|
||||
outputFormat := func(name string) string {
|
||||
return outputFormats[name]
|
||||
}
|
||||
if oc, ok := srv.(toolsrv.OutputFormatClassifier); ok {
|
||||
outputFormat = oc.OutputFormat
|
||||
}
|
||||
|
||||
var tierFn func(string, json.RawMessage) ResultTier
|
||||
if tc, ok := srv.(toolsrv.MemoryTierClassifier); ok {
|
||||
tierFn = func(name string, args json.RawMessage) ResultTier {
|
||||
switch tc.MemoryTierArgs(name, args) {
|
||||
case "cold":
|
||||
return TierCold
|
||||
case "warm":
|
||||
return TierWarm
|
||||
default:
|
||||
return TierHot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build resetsCounter lookup from tool infos.
|
||||
resetsCounterMap := make(map[string]bool, len(allToolInfos))
|
||||
for _, ti := range allToolInfos {
|
||||
if ti.ResetsCounter {
|
||||
resetsCounterMap[ti.Name] = true
|
||||
}
|
||||
}
|
||||
var resetsCounterFn func(string) bool
|
||||
if len(resetsCounterMap) > 0 {
|
||||
resetsCounterFn = func(name string) bool {
|
||||
return resetsCounterMap[name]
|
||||
}
|
||||
toolMeta[ti.Name] = ti
|
||||
}
|
||||
|
||||
var compactionModel string
|
||||
|
|
@ -124,11 +84,8 @@ func BuildRuntime(cfg *AgentConfig, srv toolsrv.Runner, cwd string, env []string
|
|||
return &Runtime{
|
||||
ToolServer: srv,
|
||||
Tools: allTools,
|
||||
ToolMeta: toolMeta,
|
||||
Exec: exec,
|
||||
CanParallelize: classify,
|
||||
OutputFormat: outputFormat,
|
||||
MemoryTier: tierFn,
|
||||
ResetsCounter: resetsCounterFn,
|
||||
Preamble: preamble,
|
||||
GenParams: genParams,
|
||||
MaxSteps: maxSteps,
|
||||
|
|
|
|||
|
|
@ -99,10 +99,22 @@ func fileStat(path string) (int64, int64) {
|
|||
}
|
||||
|
||||
func toolOutputFormat(rt *Runtime, name string) string {
|
||||
if rt.OutputFormat == nil {
|
||||
return ""
|
||||
if ti, ok := rt.ToolMeta[name]; ok {
|
||||
return ti.OutputFormat
|
||||
}
|
||||
return rt.OutputFormat(name)
|
||||
return ""
|
||||
}
|
||||
|
||||
func toolMemoryTier(rt *Runtime, name string) ResultTier {
|
||||
if ti, ok := rt.ToolMeta[name]; ok {
|
||||
switch ti.Tier {
|
||||
case "cold":
|
||||
return TierCold
|
||||
case "warm":
|
||||
return TierWarm
|
||||
}
|
||||
}
|
||||
return TierHot
|
||||
}
|
||||
|
||||
// TurnCtx holds per-turn closures and state that vary between turns within
|
||||
|
|
@ -317,7 +329,7 @@ func run(rt *Runtime, ctx TurnCtx, state state) error {
|
|||
return cr, true
|
||||
}
|
||||
emit(ctx, Event{Role: "call", Name: call.Name, Content: string(call.Arguments)})
|
||||
readSafe := rt.CanParallelize != nil && rt.CanParallelize(call.Name)
|
||||
readSafe := rt.ToolMeta[call.Name].ReadOnly
|
||||
if readSafe {
|
||||
key := call.Name + "\x00" + string(call.Arguments)
|
||||
if v, ok := resultCache.Load(key); ok {
|
||||
|
|
@ -420,14 +432,14 @@ func run(rt *Runtime, ctx TurnCtx, state state) error {
|
|||
emit(ctx, Event{Role: "tool", Name: call.Name, OutputFormat: toolOutputFormat(rt, call.Name)})
|
||||
}
|
||||
tier := TierHot
|
||||
if !isErr && rt.MemoryTier != nil {
|
||||
tier = rt.MemoryTier(call.Name, call.Arguments)
|
||||
if !isErr {
|
||||
tier = toolMemoryTier(rt, call.Name)
|
||||
}
|
||||
return toolResult{ToolCallID: call.ID, Name: call.Name, Content: result, ContentBlocks: resultBlocks, IsError: isErr, Tier: tier}, false
|
||||
}
|
||||
|
||||
isParallelSafe := func(name string) bool {
|
||||
return name != "" && rt.CanParallelize != nil && rt.CanParallelize(name)
|
||||
return name != "" && rt.ToolMeta[name].ReadOnly
|
||||
}
|
||||
|
||||
for i := 0; i < len(toolCalls) && !interrupted; {
|
||||
|
|
@ -644,9 +656,9 @@ func run(rt *Runtime, ctx TurnCtx, state state) error {
|
|||
// This allows the agent to continue working without hitting the soft
|
||||
// step-budget guardrail, as long as it's making active progress (writing
|
||||
// files, renaming symbols, etc.) rather than looping on research.
|
||||
if rt.ResetsCounter != nil {
|
||||
if rt.ToolMeta != nil {
|
||||
for _, r := range results {
|
||||
if !r.IsError && rt.ResetsCounter(r.Name) {
|
||||
if !r.IsError && rt.ToolMeta[r.Name].ResetsCounter {
|
||||
step = 0
|
||||
break
|
||||
}
|
||||
|
|
@ -1079,6 +1091,4 @@ func retryCountdown(ctx TurnCtx, wait time.Duration) error {
|
|||
// defaultToolResultMaxBytes caps tool result content sent back to the model.
|
||||
const defaultToolResultMaxBytes = 131072
|
||||
|
||||
// toolClassifier reports whether a named tool is safe to run concurrently
|
||||
// with other read-class toolsrv. nil means treat all tools as serial.
|
||||
type toolClassifier func(name string) bool
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package agent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"ollie/backend"
|
||||
"ollie/toolsrv"
|
||||
)
|
||||
|
|
@ -12,17 +10,14 @@ import (
|
|||
// agent. The agent struct stores a pointer to the active Runtime; switching
|
||||
// agents replaces it atomically.
|
||||
type Runtime struct {
|
||||
Backend backend.Backend
|
||||
ToolServer toolsrv.Runner // the execute server (tool runtime, env, cwd)
|
||||
Preamble string // compiled system prompt
|
||||
Tools []backend.Tool
|
||||
Exec toolExecutor
|
||||
CanParallelize toolClassifier
|
||||
OutputFormat func(string) string
|
||||
MemoryTier func(string, json.RawMessage) ResultTier
|
||||
ResetsCounter func(string) bool // true if tool resets step counter
|
||||
GenParams backend.GenerationParams
|
||||
MaxSteps int
|
||||
Backend backend.Backend
|
||||
ToolServer toolsrv.Runner // the execute server (tool runtime, env, cwd)
|
||||
Preamble string // compiled system prompt
|
||||
Tools []backend.Tool
|
||||
ToolMeta map[string]toolsrv.ToolInfo // keyed by tool name — source of truth for all per-tool metadata
|
||||
Exec toolExecutor
|
||||
GenParams backend.GenerationParams
|
||||
MaxSteps int
|
||||
// toolRegistryRevision tracks the last-seen tool registry revision. When the
|
||||
// registry revision advances (after tool_load/unload), the next turn
|
||||
// will detect the mismatch and refetch.
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"ollie/backend"
|
||||
"ollie/toolsrv"
|
||||
)
|
||||
|
||||
// Submit processes one line of user input: it starts an agent turn that streams
|
||||
|
|
@ -111,13 +112,11 @@ func (ag *Agent) executeTurn(ctx context.Context, input string) string {
|
|||
return ""
|
||||
}
|
||||
ag.runtime.Tools = toolInfosToBackend(ti)
|
||||
outputFormats := make(map[string]string, len(ti))
|
||||
meta := make(map[string]toolsrv.ToolInfo, len(ti))
|
||||
for _, info := range ti {
|
||||
outputFormats[info.Name] = info.OutputFormat
|
||||
}
|
||||
ag.runtime.OutputFormat = func(name string) string {
|
||||
return outputFormats[name]
|
||||
meta[info.Name] = info
|
||||
}
|
||||
ag.runtime.ToolMeta = meta
|
||||
}
|
||||
|
||||
turnCtx := TurnCtx{
|
||||
|
|
|
|||
|
|
@ -36,25 +36,3 @@ type Runner interface {
|
|||
ListTools() ([]ToolInfo, error)
|
||||
CallTool(ctx context.Context, tool string, args json.RawMessage) (json.RawMessage, error)
|
||||
}
|
||||
|
||||
// ParallelClassifier is implemented by tool servers that can report whether a
|
||||
// named tool is safe to run concurrently with other read-class tools.
|
||||
// Returns false for unknown tools (conservative default).
|
||||
type ParallelClassifier interface {
|
||||
CanParallelize(name string) bool
|
||||
}
|
||||
|
||||
// MemoryTierClassifier is implemented by tool servers that can report the retention
|
||||
// tier of a tool's results: "hot" (verbatim), "warm" (summarized on compaction),
|
||||
// or "cold" (immediately summarized). Returns "hot" for unknown tools.
|
||||
type MemoryTierClassifier interface {
|
||||
MemoryTier(name string) string
|
||||
// MemoryTierArgs classifies the tier using both the outer tool name and its
|
||||
// arguments.
|
||||
MemoryTierArgs(name string, args json.RawMessage) string
|
||||
}
|
||||
|
||||
// OutputFormatClassifier reports the source-fence language for tool output.
|
||||
type OutputFormatClassifier interface {
|
||||
OutputFormat(name string) string
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue