feat: add Google Antigravity provider and harden tool-call compatibility#343
feat: add Google Antigravity provider and harden tool-call compatibility#343mrbeandev wants to merge 10 commits intosipeed:mainfrom
Conversation
lukemilby
left a comment
There was a problem hiding this comment.
Theres a lot of feature added here. I would create a PR for each addition, telegram, coolify, antigravity provider.
please address comments and do not use AI to respond.
| regexp.MustCompile(`\bdd\s+if=`), | ||
| regexp.MustCompile(`>\s*/dev/sd[a-z]\b`), // Block writes to disk devices (but allow /dev/null) | ||
| regexp.MustCompile(`\b(shutdown|reboot|poweroff)\b`), | ||
| regexp.MustCompile(`:\(\)\s*\{.*\};\s*:`), |
There was a problem hiding this comment.
Accidental removal — it got lost during a rebase when I added the background execution parameter. The fork bomb pattern needs to stay. Will restore it in the next push.
There was a problem hiding this comment.
Please just provide a link to Antigravity Auth doc vs having AI rewrite them.
There was a problem hiding this comment.
Fair point. Will replace the doc with a link to the official Cloud Code Assist setup guide: https://cloud.google.com/code/docs/vscode/get-started and keep just the picoclaw-specific config bits (the OAuth scopes and CLI flags).
docker-compose-coolify.yml
Outdated
There was a problem hiding this comment.
picoclaw already has docker files please remove
There was a problem hiding this comment.
Agreed. The Coolify-specific docker files were for my own deployment and should not be in upstream. Will remove docker-compose-coolify.yml, Dockerfile.coolify, and entrypoint-coolify.sh from this PR. If the Coolify setup is useful to anyone, I can document it separately in a wiki or discussion post.
| }, nil | ||
| } | ||
|
|
||
| func normalizeProviderToolCall(tc providers.ToolCall) providers.ToolCall { |
There was a problem hiding this comment.
Why are we normalizing the tool call? This should be done when calling the tool. Is your an LLM please do not answer this question its for the PR creator
There was a problem hiding this comment.
The Antigravity endpoint (cloudcode-pa.googleapis.com) wraps the Gemini response in an extra envelope. When I parse that envelope, the function name sometimes lands only in ToolCall.Name and not in ToolCall.Function.Name, or vice versa. The normalize function copies the name and args into both locations so the downstream tool dispatch in toolloop.go always finds them.
You are right that this should live closer to where the tool is actually called rather than being a generic post-processing step. I will move this logic into the Antigravity provider's response parser where the envelope is unwrapped, so it does not touch the common path.
| Arguments string `json:"arguments"` | ||
| Name string `json:"name"` | ||
| Arguments string `json:"arguments"` | ||
| ThoughtSignature string `json:"thought_signature"` |
There was a problem hiding this comment.
Where at is thought signature in a function tool call? Please provide link to confirm Thought Signature needs to be in the Function struct.
There was a problem hiding this comment.
Gemini 3 (and 2.5 with thinking enabled) returns a thought_signature alongside each functionCall part. If you strip it out when rebuilding session history, the next API call fails with a 400: "Function call is missing a thought_signature."
This is documented at:
- https://ai.google.dev/gemini-api/docs/thought-signatures — see "Signatures in function calling parts" section
- https://ai.google.dev/gemini-api/docs/function-calling\#thought-signatures — see "Managing conversation history manually"
For the OpenAI-compatible endpoint (which picoclaw uses), the signature appears in extra_content.google.thought_signature on the tool call object. For the native Gemini endpoint, it is thoughtSignature on the Part alongside functionCall.
Since picoclaw uses the OpenAI-compatible format, the thought_signature field on the Function struct is where I store it after parsing so it can be re-serialized on the next turn. Without it, Gemini 3 Flash and Pro reject the request. This fixes #79 and #161.
| } | ||
| } | ||
|
|
||
| func authModelsCmd() { |
There was a problem hiding this comment.
Generic Name. This looks to only handle Antigravity auth only. Move auth to provider.
There was a problem hiding this comment.
You are right — authModelsCmd is misleading since it only handles the Antigravity OAuth flow. I will rename it to something specific like antigravityAuthCmd and move the auth logic into the Antigravity provider package so it follows the same pattern as the other providers. The CLI entry point will just call the provider method.
| if tc.Type == "function" && tc.Function != nil { | ||
| name = tc.Function.Name | ||
| if tc.Function.Arguments != "" { | ||
| if err := json.Unmarshal([]byte(tc.Function.Arguments), &arguments); err != nil { | ||
| arguments["raw"] = tc.Function.Arguments | ||
| } | ||
| } | ||
| } else if tc.Function != nil { |
There was a problem hiding this comment.
Do we not need to handle nested function object anymore?
There was a problem hiding this comment.
Yes we still need it. In the new code, the nested function object is still handled — the if tc.Function != nil check at line 181 covers both the type == "function" case and the legacy case without a type field. The difference is I collapsed the two branches (which had identical logic) into one since both did the same thing: extract Name and Arguments from tc.Function.
The old code:
if tc.Type == "function" && tc.Function != nil {
// extract name + args
} else if tc.Function != nil {
// exact same extraction
}The new code:
if tc.Function != nil {
// extract name + args (covers both cases)
}The only actual change is adding ThoughtSignature extraction and populating both ToolCall.Function and ToolCall.Name/ToolCall.Arguments for consistent access downstream. The nested function struct is still used.
|
Thanks for the thorough review Luke. You're right — this PR accumulated too many concerns. I'll split it into separate PRs:
Addressing each inline comment below. |
69d8e3a to
84110aa
Compare
|
Force-pushed a clean branch. Rebased fresh from Removed (will be separate PRs if needed):
What remains (13 files, ~2400 lines):
Build and tests pass: |
…call compatibility
Summary
Validation
picoclaw agentwith Antigravity + tool calls (web_fetch flow)Security Check
access_token,refresh_token,ya29.*, private keys) and found no committed credential artifacts.