@@ -15,52 +15,76 @@ export function resetToolTrackerCount(tracker: ToolTracker): void {
1515}
1616
1717/**
18- * Counts total tool results in OpenAI/Anthropic messages (without tracker).
19- * Used for determining if nudge threshold is met.
18+ * Track new tool results in OpenAI/Anthropic messages.
19+ * Increments toolResultCount only for tools not already seen.
20+ * Returns the number of NEW tools found (since last call).
2021 */
21- export function countToolResults ( messages : any [ ] ) : number {
22- let count = 0
22+ export function trackNewToolResults ( messages : any [ ] , tracker : ToolTracker ) : number {
23+ let newCount = 0
2324 for ( const m of messages ) {
24- if ( m . role === 'tool' ) {
25- count ++
25+ if ( m . role === 'tool' && m . tool_call_id ) {
26+ if ( ! tracker . seenToolResultIds . has ( m . tool_call_id ) ) {
27+ tracker . seenToolResultIds . add ( m . tool_call_id )
28+ tracker . toolResultCount ++
29+ newCount ++
30+ }
2631 } else if ( m . role === 'user' && Array . isArray ( m . content ) ) {
2732 for ( const part of m . content ) {
28- if ( part . type === 'tool_result' ) {
29- count ++
33+ if ( part . type === 'tool_result' && part . tool_use_id ) {
34+ if ( ! tracker . seenToolResultIds . has ( part . tool_use_id ) ) {
35+ tracker . seenToolResultIds . add ( part . tool_use_id )
36+ tracker . toolResultCount ++
37+ newCount ++
38+ }
3039 }
3140 }
3241 }
3342 }
34- return count
43+ return newCount
3544}
3645
3746/**
38- * Counts total tool results in Gemini contents (without tracker).
47+ * Track new tool results in Gemini contents.
48+ * Uses position-based tracking since Gemini doesn't have tool call IDs.
49+ * Returns the number of NEW tools found (since last call).
3950 */
40- export function countToolResultsGemini ( contents : any [ ] ) : number {
41- let count = 0
51+ export function trackNewToolResultsGemini ( contents : any [ ] , tracker : ToolTracker ) : number {
52+ let newCount = 0
53+ let positionCounter = 0
4254 for ( const content of contents ) {
4355 if ( ! Array . isArray ( content . parts ) ) continue
4456 for ( const part of content . parts ) {
4557 if ( part . functionResponse ) {
46- count ++
58+ // Use position-based ID since Gemini doesn't have tool_call_id
59+ const positionId = `gemini_pos_${ positionCounter } `
60+ positionCounter ++
61+ if ( ! tracker . seenToolResultIds . has ( positionId ) ) {
62+ tracker . seenToolResultIds . add ( positionId )
63+ tracker . toolResultCount ++
64+ newCount ++
65+ }
4766 }
4867 }
4968 }
50- return count
69+ return newCount
5170}
5271
5372/**
54- * Counts total tool results in OpenAI Responses API input (without tracker).
73+ * Track new tool results in OpenAI Responses API input.
74+ * Returns the number of NEW tools found (since last call).
5575 */
56- export function countToolResultsResponses ( input : any [ ] ) : number {
57- let count = 0
76+ export function trackNewToolResultsResponses ( input : any [ ] , tracker : ToolTracker ) : number {
77+ let newCount = 0
5878 for ( const item of input ) {
59- if ( item . type === 'function_call_output' ) {
60- count ++
79+ if ( item . type === 'function_call_output' && item . call_id ) {
80+ if ( ! tracker . seenToolResultIds . has ( item . call_id ) ) {
81+ tracker . seenToolResultIds . add ( item . call_id )
82+ tracker . toolResultCount ++
83+ newCount ++
84+ }
6185 }
6286 }
63- return count
87+ return newCount
6488}
6589
6690// ============================================================================
0 commit comments