perf(background-agent): use Set for countedToolPartIDs, cache circuit breaker settings, optimize loop detector

- Replace countedToolPartIDs string[] with Set<string> for O(1) has/add vs O(n) includes/spread (C2)
- Cache resolveCircuitBreakerSettings at manager level to avoid repeated object creation (C3)
- Optimize recordToolCall to avoid full array copy with slice (L1)
This commit is contained in:
YeonGyu-Kim
2026-03-18 14:18:38 +09:00
parent 952bd5338d
commit 2da19fe608
4 changed files with 8 additions and 4 deletions
@@ -44,7 +44,9 @@ export function recordToolCall(
): ToolCallWindow { ): ToolCallWindow {
const previous = window?.toolSignatures ?? [] const previous = window?.toolSignatures ?? []
const signature = createToolCallSignature(toolName, toolInput) const signature = createToolCallSignature(toolName, toolInput)
const toolSignatures = [...previous, signature].slice(-settings.windowSize) const toolSignatures = previous.length >= settings.windowSize
? [...previous.slice(1), signature]
: [...previous, signature]
return { return {
toolSignatures, toolSignatures,
@@ -233,7 +233,7 @@ describe("BackgroundManager circuit breaker", () => {
expect(task.status).toBe("running") expect(task.status).toBe("running")
expect(task.progress?.toolCalls).toBe(1) expect(task.progress?.toolCalls).toBe(1)
expect(task.progress?.countedToolPartIDs).toEqual(["tool-1"]) expect(task.progress?.countedToolPartIDs).toEqual(new Set(["tool-1"]))
}) })
}) })
+3 -1
View File
@@ -57,6 +57,7 @@ import {
detectRepetitiveToolUse, detectRepetitiveToolUse,
recordToolCall, recordToolCall,
resolveCircuitBreakerSettings, resolveCircuitBreakerSettings,
type CircuitBreakerSettings,
} from "./loop-detector" } from "./loop-detector"
import { import {
createSubagentDepthLimitError, createSubagentDepthLimitError,
@@ -152,6 +153,7 @@ export class BackgroundManager {
private preStartDescendantReservations: Set<string> private preStartDescendantReservations: Set<string>
private enableParentSessionNotifications: boolean private enableParentSessionNotifications: boolean
readonly taskHistory = new TaskHistory() readonly taskHistory = new TaskHistory()
private cachedCircuitBreakerSettings?: CircuitBreakerSettings
constructor( constructor(
ctx: PluginInput, ctx: PluginInput,
@@ -918,7 +920,7 @@ export class BackgroundManager {
task.progress.toolCalls += 1 task.progress.toolCalls += 1
task.progress.lastTool = partInfo.tool task.progress.lastTool = partInfo.tool
const circuitBreaker = resolveCircuitBreakerSettings(this.config) const circuitBreaker = this.cachedCircuitBreakerSettings ?? (this.cachedCircuitBreakerSettings = resolveCircuitBreakerSettings(this.config))
if (partInfo.tool) { if (partInfo.tool) {
task.progress.toolCallWindow = recordToolCall( task.progress.toolCallWindow = recordToolCall(
task.progress.toolCallWindow, task.progress.toolCallWindow,
+1 -1
View File
@@ -19,7 +19,7 @@ export interface TaskProgress {
toolCalls: number toolCalls: number
lastTool?: string lastTool?: string
toolCallWindow?: ToolCallWindow toolCallWindow?: ToolCallWindow
countedToolPartIDs?: string[] countedToolPartIDs?: Set<string>
lastUpdate: Date lastUpdate: Date
lastMessage?: string lastMessage?: string
lastMessageAt?: Date lastMessageAt?: Date