Skip to content

Only last state change for multiple tool calls is being committed to state #354

@verdverm

Description

@verdverm

I have some custom functiontools and the LLM is calling it in batch via message parts. In those functiontools, I update the state, which is what the docs say to do: https://google.github.io/adk-docs/sessions/state/#a-warning-about-direct-state-modification

It looks like only the last tool call's state is being applied to the delta. I have confirmed the tools is called many times in one turn

Example state modifying functiontool

const CacheRemoveTool = "cache_remove"
const CacheRemoveDesc = `
adds or overwrites an entry in your working key/value cache and context
`

type CacheRemoveArgs struct {
	Key string `json:"key"` // path to a directory
}
type CacheRemoveResult struct {
	Key    string `json:"key"`    // path to a directory
	Status string `json:"status"` // "ok" or "error"
	Error  string `json:"error,omitempty"`
}

func NewCacheRemove() (tool.Tool, error) {
	handler := func(ctx tool.Context, input CacheRemoveArgs) (CacheRemoveResult, error) {
		k := fmt.Sprintf("cache:%s:%s", ctx.AgentName(), input.Key)
		fmt.Println("CACHE.REMOVE!", k)

		err := ctx.State().Set(k, nil)
		if err != nil {
			return CacheRemoveResult{Status: "error", Key: input.Key, Error: err.Error()}, err
		}
		return CacheRemoveResult{Status: "ok", Key: input.Key}, nil
	}
	return functiontool.New(functiontool.Config{
		Name:        CacheRemoveTool,
		Description: strings.TrimSpace(CacheRemoveDesc),
	}, handler)
}

Event with bulk functionCall

{
  "Content": {
    "parts": [
      {
        "text": "That is an insightful observation. Keeping the key with a marker like \"no relevant\" is a good way to maintain a memory of explored files without cluttering the context with content.\n\nI will now attempt to update a batch of keys using `cache_write` to see if it suffers from the same \"only the last command commits\" bug. I will use the marker value `\"no relevant\"` for the keys that currently show `<no value>` but have been examined.\n\nI will use the following keys for the test:\n1.  `package.json`\n2.  `src/main.tsx`\n3.  `src/App.tsx`\n4.  `src/vscodeApi.ts` (This will be the final command to see if it's the only one that persists)\n\n"
      },
      {
        "functionCall": {
          "id": "adk-3caaaeab-b818-4967-8a06-cf57908d0a72",
          "args": {
            "key": "package.json",
            "value": "no relevant"
          },
          "name": "cache_write"
        }
      },
      {
        "functionCall": {
          "id": "adk-7b44dc4e-205d-4882-b8c3-63dcec005eeb",
          "args": {
            "key": "src/main.tsx",
            "value": "no relevant"
          },
          "name": "cache_write"
        }
      },
      {
        "functionCall": {
          "id": "adk-60a05b82-cbfd-441f-a565-fd966db0d92f",
          "args": {
            "key": "src/App.tsx",
            "value": "no relevant"
          },
          "name": "cache_write"
        }
      },
      {
        "functionCall": {
          "id": "adk-dd68d7e9-08ee-4ba1-96d1-06784bdd4e89",
          "args": {
            "key": "src/vscodeApi.ts",
            "value": "no relevant"
          },
          "name": "cache_write"
        }
      }
    ],
    "role": "model"
  },
  "CitationMetadata": null,
  "GroundingMetadata": null,
  "UsageMetadata": {
    "cacheTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 6772
      }
    ],
    "cachedContentTokenCount": 6772,
    "candidatesTokenCount": 284,
    "promptTokenCount": 7262,
    "promptTokensDetails": [
      {
        "modality": "TEXT",
        "tokenCount": 7262
      }
    ],
    "totalTokenCount": 7546
  },
  "CustomMetadata": null,
  "LogprobsResult": null,
  "Partial": false,
  "TurnComplete": false,
  "Interrupted": false,
  "ErrorCode": "",
  "ErrorMessage": "",
  "FinishReason": "",
  "AvgLogprobs": 0,
  "ID": "2bf8cec9-5805-4209-832e-0eb085ef133a",
  "Timestamp": "2025-11-24T21:00:10.756461-08:00",
  "InvocationID": "e-f9ed648d-d584-49f5-9c5d-ebaa54c5ef07",
  "Branch": "",
  "Author": "hack",
  "Actions": {
    "StateDelta": {},
    "ArtifactDelta": null,
    "SkipSummarization": false,
    "TransferToAgent": "",
    "Escalate": false
  },
  "LongRunningToolIDs": null
}

Event with bulk functionResponse

{
  "Content": {
    "parts": [
      {
        "functionResponse": {
          "id": "adk-3caaaeab-b818-4967-8a06-cf57908d0a72",
          "name": "cache_write",
          "response": {
            "key": "package.json",
            "status": "ok"
          }
        }
      },
      {
        "functionResponse": {
          "id": "adk-7b44dc4e-205d-4882-b8c3-63dcec005eeb",
          "name": "cache_write",
          "response": {
            "key": "src/main.tsx",
            "status": "ok"
          }
        }
      },
      {
        "functionResponse": {
          "id": "adk-60a05b82-cbfd-441f-a565-fd966db0d92f",
          "name": "cache_write",
          "response": {
            "key": "src/App.tsx",
            "status": "ok"
          }
        }
      },
      {
        "functionResponse": {
          "id": "adk-dd68d7e9-08ee-4ba1-96d1-06784bdd4e89",
          "name": "cache_write",
          "response": {
            "key": "src/vscodeApi.ts",
            "status": "ok"
          }
        }
      }
    ],
    "role": "user"
  },
  "CitationMetadata": null,
  "GroundingMetadata": null,
  "UsageMetadata": null,
  "CustomMetadata": null,
  "LogprobsResult": null,
  "Partial": false,
  "TurnComplete": false,
  "Interrupted": false,
  "ErrorCode": "",
  "ErrorMessage": "",
  "FinishReason": "",
  "AvgLogprobs": 0,
  "ID": "d635feb2-4f3a-4353-9cb5-80b713e567b8",
  "Timestamp": "2025-11-24T21:00:10.76217-08:00",
  "InvocationID": "e-f9ed648d-d584-49f5-9c5d-ebaa54c5ef07",
  "Branch": "",
  "Author": "hack",
  "Actions": {
    "StateDelta": {
      "cache:hack:src/vscodeApi.ts": "no relevant"
    },
    "ArtifactDelta": null,
    "SkipSummarization": false,
    "TransferToAgent": "",
    "Escalate": false
  },
  "LongRunningToolIDs": null
}

Multiple tool calls in the logs

Chatting payload: handlers.ChatPayload{Text:"ok, we can see the right logs now. Try a bulk operation to write \"not relevant\" to all the cache keys", Sid:"065471a3-969a-4dc1-bc49-a3a4bcf9bcc3", Agent:"hack", Model:"gemini-2.5-flash"}
userMsg &{[0x140004ea230] user} map[env:map[clipboard:WRITE machineId:cf912dbf5f56042166332d2be6fdf1e21f8155680986088029fbcbf130665dda sid:065471a3-969a-4dc1-bc49-a3a4bcf9bcc3 user:verdverm vscodeSid:0ac5806d-099c-44ea-aa35-ea7c7005b2fc1764048527260 workspaceDir:/Users/tony/hof/hof/extensions/vscode/webviews/chat]]

BAC.hack
renderInstructions.Agent hack

BMC.hack

AMC.hack
model.LLMResponse{Content:(*genai.Content)(0x14000b5cde0), CitationMetadata:(*genai.CitationMetadata)(nil), GroundingMetadata:(*genai.GroundingMetadata)(nil), UsageMetadata:(*genai.GenerateContentResponseUsageMetadata)(0x14000858750), CustomMetadata:map[string]interface {}(nil), LogprobsResult:(*genai.LogprobsResult)(nil), Partial:false, TurnComplete:false, Interrupted:false, ErrorCode:"", ErrorMessage:"", FinishReason:"STOP", AvgLogprobs:0}
chat.event: &{{0x14000b5cde0 <nil> <nil> 0x14000858750 map[] <nil> false false false   STOP 0} d340e2dd-ed3b-4e8c-8376-5c89c45f46e0 2025-11-24 21:30:43.717199 -0800 PST m=+123.955414043 e-32938734-d387-4cfb-afe2-3de23b201181  hack {map[] map[] false  false} []}

BTC.hack.cache_write map[key:. value:not relevant]
CACHE.WRITE: cache:hack:.

ATC.hack.cache_write map[key:. value:not relevant] map[key:. status:ok]

BTC.hack.cache_write map[key:package.json value:not relevant]
CACHE.WRITE: cache:hack:package.json

ATC.hack.cache_write map[key:package.json value:not relevant] map[key:package.json status:ok]

BTC.hack.cache_write map[key:src value:not relevant]
CACHE.WRITE: cache:hack:src

ATC.hack.cache_write map[key:src value:not relevant] map[key:src status:ok]

BTC.hack.cache_write map[key:src/App.tsx value:not relevant]
CACHE.WRITE: cache:hack:src/App.tsx

ATC.hack.cache_write map[key:src/App.tsx value:not relevant] map[key:src/App.tsx status:ok]

BTC.hack.cache_write map[key:src/components value:not relevant]
CACHE.WRITE: cache:hack:src/components

ATC.hack.cache_write map[key:src/components value:not relevant] map[key:src/components status:ok]

BTC.hack.cache_write map[key:src/components/Header.tsx value:not relevant]
CACHE.WRITE: cache:hack:src/components/Header.tsx

ATC.hack.cache_write map[key:src/components/Header.tsx value:not relevant] map[key:src/components/Header.tsx status:ok]

BTC.hack.cache_write map[key:src/components/Messages.tsx value:not relevant]
CACHE.WRITE: cache:hack:src/components/Messages.tsx

ATC.hack.cache_write map[key:src/components/Messages.tsx value:not relevant] map[key:src/components/Messages.tsx status:ok]

BTC.hack.cache_write map[key:src/main.tsx value:not relevant]
CACHE.WRITE: cache:hack:src/main.tsx

ATC.hack.cache_write map[key:src/main.tsx value:not relevant] map[key:src/main.tsx status:ok]

BTC.hack.cache_write map[key:src/vscodeApi.ts value:not relevant]
CACHE.WRITE: cache:hack:src/vscodeApi.ts

ATC.hack.cache_write map[key:src/vscodeApi.ts value:not relevant] map[key:src/vscodeApi.ts status:ok]
chat.event: &{{0x14000a919e0 <nil> <nil> <nil> map[] <nil> false false false    0} 504e260a-8bc1-4b5a-91ae-4790f149eacf 2025-11-24 21:30:43.722247 -0800 PST m=+123.960462543 e-32938734-d387-4cfb-afe2-3de23b201181  hack {map[cache:hack:src/vscodeApi.ts:not relevant] map[] false  false} []}
renderInstructions.Agent hack

BMC.hack

AMC.hack
model.LLMResponse{Content:(*genai.Content)(0x14000c19470), CitationMetadata:(*genai.CitationMetadata)(nil), GroundingMetadata:(*genai.GroundingMetadata)(nil), UsageMetadata:(*genai.GenerateContentResponseUsageMetadata)(0x14000b0c240), CustomMetadata:map[string]interface {}(nil), LogprobsResult:(*genai.LogprobsResult)(nil), Partial:false, TurnComplete:false, Interrupted:false, ErrorCode:"", ErrorMessage:"", FinishReason:"STOP", AvgLogprobs:0}
chat.event: &{{0x14000c19470 <nil> <nil> 0x14000b0c240 map[] <nil> false false false   STOP 0} b8b6d228-20c2-4732-bd97-f2db9822ced8 2025-11-24 21:30:44.467564 -0800 PST m=+124.705775334 e-32938734-d387-4cfb-afe2-3de23b201181  hack {map[] map[] false  false} []}

AAC.hack

Legend:

BAC: BeforeAgentCallback
BMC: BeforeModelCallback
BTC: BeforeToolCallback

ATC: AfterToolCallback
AMC: AfterModelCallback
AAC: AfterAgentCallback

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions