Advanced design extension — not implemented in the pinned app
PocketChat's resource buttons open reviewed URLs after a user tap. They are not Gemini function calls. A future tool integration might let Gemini propose a saved note or request an approved search over local notes. That requires a separate executor and a bounded response loop.
A proposal is not permission
Model output is untrusted input. Declare a narrow tool name and argument schema, validate the arguments, check application permissions, and ask for user confirmation before a write. Do not let a model-supplied account ID decide ownership. If note contents are sent back to Gemini, disclose that transfer before the read.
// Proposed executor boundary; not part of the baseline.
data class SaveNoteProposal(val callId: String, val title: String, val text: String)
sealed interface Approval {
data object Pending : Approval
data object Rejected : Approval
data object Granted : Approval
}
The proposal's call identity should be tied to persisted execution state. A duplicate delivery after a timeout must return the previous result or safely resume the same operation, not create another saved note. A stable ID alone is insufficient unless the deduplication record and side effect are coordinated transactionally.
Bound the loop
Limit tool rounds, execution time, argument size, and result size. Reject unknown tool names. A denied approval is a meaningful result, not a reason to ask repeatedly. Keep output from retrieved notes as data; it must not rewrite the executor's rules.
Check your understanding
What happens if the model claims “the user already approved”? The application checks its own approval state. What happens if a save succeeded but the response was lost? A retry with the same execution identity must not duplicate the write. Design these cases before adding a tool declaration to a request.