Add focused GenAIApp samples#79
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis pull request adds 15+ Google Apps Script sample files and a comprehensive README rewrite: new samples demonstrate basic and system chats, multi-model runs, function calling, multimodal inputs (images/docs/knowledge links), vector-store RAG, conversation continuation/configuration, and integrations with Sheets, web browsing, MCP connectors, and Vertex AI. ChangesSample Suite Expansion
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches✨ Simplify code
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6f1ee60be
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@samples/conversation-continuation.gs`:
- Around line 14-19: The sample assumes retrieveLastResponseId() always returns
a value; add a null guard around previousResponseId (the value returned by
retrieveLastResponseId()) before calling setPreviousResponseId on the new chat.
If previousResponseId is null/undefined, log or handle it and create the new
chat without .setPreviousResponseId(...) (or bail out), otherwise pass the ID
into GenAIApp.newChat().setPreviousResponseId(previousResponseId). Ensure
references to previousResponseId, retrieveLastResponseId, and
GenAIApp.newChat().setPreviousResponseId are used so the change is easy to
locate.
In `@samples/document-analysis.gs`:
- Around line 11-17: Validate the driveFileId returned by
scriptProperties.getProperty('SAMPLE_PDF_FILE_ID') before calling
GenAIApp.newChat().addFile(...): after obtaining driveFileId (variable
driveFileId), check that it's non-empty/null and if not present either throw a
clear error or log and return early so that the subsequent .addFile(driveFileId)
call is never invoked with an invalid value; update the block around
GenAIApp.newChat()/.addFile() to gate adding the Drive file and only call
addFile(driveFileId) when the guard passes.
In `@samples/image-analysis.gs`:
- Line 11: The code calls UrlFetchApp.fetch(...) and immediately builds
imageBlob, which can mask HTTP errors; instead call UrlFetchApp.fetch(imageUrl)
into a response variable (e.g., imageResponse), check response.getResponseCode()
for success (200) and handle non-200 cases (throw or log a clear error
mentioning the status and URL), and only then call
response.getBlob().setName('apps-script-logo.png') to create imageBlob; update
references to use the new imageResponse/imageBlob variables and ensure failures
are surfaced with actionable messages.
In `@samples/sheets-ai-assistant.gs`:
- Around line 7-12: In sheetsAiAssistantSample, guard the call to
GenAIApp.setOpenAIAPIKey by reading
PropertiesService.getScriptProperties().getProperty('OPENAI_API_KEY') into a
variable, check for null/empty, and if missing throw or log a clear error (e.g.,
throw new Error('OPENAI_API_KEY not set')) before calling setOpenAIAPIKey;
update the code around setOpenAIAPIKey and the OPENAI_API_KEY retrieval so the
sample fails fast with a clear message rather than passing null into
setOpenAIAPIKey.
- Around line 18-25: The response from GenAIApp.newChat().run({ model:
'gpt-5.4', max_tokens: 800 }) can be string|null, so before calling
outputSheet.getRange('A1').setValue(response) ensure you handle a null fallback
(e.g., substitute '' when response is null); update the code around
GenAIApp.newChat().run and the outputSheet.getRange('A1').setValue call to use
the non-null string (or empty string) so setValue always receives a string.
In `@samples/simple-chat.gs`:
- Line 8: Before calling GenAIApp.setOpenAIAPIKey(...), guard against a missing
script property by retrieving the key using
PropertiesService.getScriptProperties().getProperty('OPENAI_API_KEY'), checking
if the result is null/empty, and failing fast with a clear error (throw or log
and return) if it is absent; then pass the validated non-empty key into
GenAIApp.setOpenAIAPIKey so callers get an explicit message instead of opaque
failures.
In `@samples/vertex-ai-setup.gs`:
- Line 17: The sample uses a hardcoded model identifier in the chat.run call
(chat.run({ model: 'gemini-2.5-flash' })); add a one-line comment or header just
above that call stating this is a sample default model name users may want to
change (e.g., "Sample default model; replace with your preferred model ID"), so
callers understand they can swap 'gemini-2.5-flash' (and other examples like
'gpt-5.4') for their environment.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 0f6d304a-69aa-494a-8355-4ac5a3284f4c
📒 Files selected for processing (15)
samples/configuration-options.gssamples/conversation-continuation.gssamples/document-analysis.gssamples/function-calling-advanced.gssamples/function-calling-basics.gssamples/image-analysis.gssamples/knowledge-links.gssamples/mcp-connectors.gssamples/multi-model-usage.gssamples/sheets-ai-assistant.gssamples/simple-chat.gssamples/system-prompts.gssamples/vector-store-rag.gssamples/vertex-ai-setup.gssamples/web-browsing.gs
📜 Review details
🔇 Additional comments (10)
samples/system-prompts.gs (1)
7-16: LGTM!samples/multi-model-usage.gs (1)
7-20: LGTM!samples/knowledge-links.gs (1)
7-16: LGTM!samples/function-calling-basics.gs (1)
7-31: LGTM!samples/function-calling-advanced.gs (1)
7-39: LGTM!samples/configuration-options.gs (1)
7-20: LGTM!samples/web-browsing.gs (1)
10-14: ⚡ Quick winFix:
enableBrowsingexpects a URL string (scheme included) for the optional restriction
The library signature isenableBrowsing(scope, url)and the JSDoc documentsurlas “A specific site…”. The README and examples pass full URLs likehttps://support.google.com, matching how the sample useshttps://developers.google.com.> Likely an incorrect or invalid review comment.samples/vector-store-rag.gs (1)
16-35: ⚡ Quick winNo change needed:
addVectorStores(vectorStore.getId())andsetChunkingStrategy(800, 200)match the library’s API.
addVectorStores(vectorStoreIds)takes a string (comma-separated ids), so passing a single id works.setChunkingStrategy(maxChunkSize, chunkOverlap)uses(800, 200)in the correct order, andcreateVectorStore,uploadAndAttachFile,onlyReturnChunks, andsetMaxChunksexist as used.samples/vertex-ai-setup.gs (1)
9-12: ⚡ Quick win
GenAIApp.setGeminiAuthis called with the correct positional parameters.
The library signature issetGeminiAuth(gcp_project_id, gcp_project_region)(project id first, region second), so the sample’ssetGeminiAuth(GCP_PROJECT_ID, GCP_REGION || 'us-central1')matches. IfGCP_PROJECT_IDis unset, Gemini requests throw an explicit error (!geminiKey && !gcpProjectId) rather than silently misconfiguring.samples/mcp-connectors.gs (1)
10-18: ⚡ Quick winMCP connector sample API matches the library surface.
GenAIApp.newConnector(),setConnectorId('gmail'|'calendar'|'drive'),setAuthorization(token),setRequireApproval('never'|'domain'|'always'), andchat.addMCP(connectorObject)all exist with the expected names/signatures, so the snippet can remain as-is.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@samples/document-analysis.gs`:
- Around line 11-27: The sample asserts a Drive+Blob usage but only attaches a
Blob (textBlob) to the chat; update the implementation to match the documented
contract by retrieving the Drive file using SAMPLE_PDF_FILE_ID (e.g., via
DriveApp.getFileById or equivalent) and attach that Drive file to the
GenAIApp.newChat() (using .addFile or the API method that accepts Drive files),
or alternatively change the header/config to state this sample uses a plain Blob
only; reference textBlob, GenAIApp.newChat(), .addFile, and SAMPLE_PDF_FILE_ID
when making the fix.
In `@samples/multi-model-usage.gs`:
- Around line 9-10: The sample sets API keys without validating them; add
fail-fast guards that read scriptProperties.getProperty('OPENAI_API_KEY') and
scriptProperties.getProperty('GEMINI_API_KEY') into local variables, check for
null/empty, and if missing call Logger.log or throw an informative Error (e.g.,
"OPENAI_API_KEY missing in script properties") before calling
GenAIApp.setOpenAIAPIKey or GenAIApp.setGeminiAPIKey; apply the same pattern for
any other API key reads in the file (the lines around the GenAIApp.set* calls).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2fcf09ab-61dd-43ea-bd60-c9c46f9d344c
📒 Files selected for processing (2)
samples/document-analysis.gssamples/multi-model-usage.gs
…amples-section Refine README: add prominent Samples section and reorganize API guide
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@README.md`:
- Around line 294-300: The Gemini model list is inconsistent: update the Gemini
entry that currently lists `gemini-2.5-pro` and `gemini-2.5-flash` to include
`gemini-2.5-flash-lite` and `gemini-2.5-flash-native-audio` so it matches the
`function_call` warning; modify the Gemini list line (the one containing
"Gemini: `gemini-2.5-pro` and `gemini-2.5-flash`") to include all four variants
with backticks and keep the warning text as-is so both sections are consistent.
- Line 270: Update the markdown note so the code span for the bearer prefix
doesn't include the trailing space: rephrase the sentence around
`ScriptApp.getOAuthToken()` and `.setAuthorization()` to show `Bearer` (no
trailing space in the code span) and explicitly indicate that a space must
follow the token separator (e.g., mention "a space follows `Bearer`" or write
`Bearer` + " " outside the code span) so the semantic trailing space is
preserved without violating MD038.
- Around line 110-117: Update the README’s oauthScopes example to note that the
shown "oauthScopes" array is a starting point and that Google Workspace MCP
connectors (Gmail, Calendar, Drive) require additional service-specific scopes;
explicitly call out examples such as
https://www.googleapis.com/auth/gmail.readonly,
https://www.googleapis.com/auth/calendar, and
https://www.googleapis.com/auth/drive.readonly and state that the exact scopes
depend on which connectors (Gmail, Calendar, Drive) and operations are used so
authors must add the corresponding scopes to the "oauthScopes" manifest entry.
🪄 Autofix (Beta)
✅ Autofix completed
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b43ec3e2-6d35-4f33-b17b-51d87a69f5f6
📒 Files selected for processing (1)
README.md
📜 Review details
🧰 Additional context used
🪛 markdownlint-cli2 (0.22.1)
README.md
[warning] 270-270: Spaces inside code span elements
(MD038, no-space-in-code)
🔇 Additional comments (8)
README.md (8)
3-48: LGTM!
50-100: LGTM!
119-144: LGTM!
146-184: LGTM!
186-239: LGTM!
304-342: LGTM!
344-419: LGTM!
420-430: LGTM!
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Fixes Applied SuccessfullyFixed 1 file(s) based on 3 unresolved review comments. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 1 file(s) based on 3 unresolved review comments. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@README.md`:
- Around line 296-299: Update the README model list and adjacent warning to
exactly match the implemented run() contract in src/code.gs: include the
additional Gemini entries (e.g., gemini-3.1-pro-preview, gemini-3.1-flash-lite,
gemini-3-flash-preview, gemini-3.5-flash) and OpenAI gpt-5.5 along with the
already-listed Gemini 2.5 variants and gpt-5/gpt-5.4/o4-mini/o3; ensure the
README wording mirrors the run() documentation and any capability/compatibility
warnings so they stay in sync with the run() behavior and model names referenced
in src/code.gs.
🪄 Autofix (Beta)
✅ Autofix completed
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Fixes Applied SuccessfullyFixed 1 file(s) based on 1 unresolved review comment. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
README.md (2)
413-418:⚠️ Potential issue | 🟠 MajorConnectorObject API methods not found in codebase
The README documents
ConnectorObjectmethods (setLabel,setDescription,setServerUrl,setConnectorId,setAuthorization,setRequireApproval) with specific enum values, but a code search undersrc/did not find any implementations for these methods (no matches for the expected method patterns). Update the docs or implement/locateConnectorObjectso its actual method names/signatures and enum values match the documented API.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` around lines 413 - 418, The README lists ConnectorObject methods (setLabel, setDescription, setServerUrl, setConnectorId, setAuthorization, setRequireApproval) and enum values that are not present in the src/ codebase; either implement those methods on the ConnectorObject/class used in the codebase (create methods with the exact names and signatures, e.g., setLabel(label: string), setConnectorId(connectorId: 'gmail' | 'calendar' | 'drive'), setRequireApproval(mode: 'never' | 'domain' | 'always'), etc.), or update the README to match the actual API surface (rename the documented methods/enum values to the real method names in the ConnectorObject implementation). Locate the ConnectorObject class/function in the repo and ensure its public API matches the README, or synchronously change the README to reflect the implemented method names and allowed values.
280-280:⚠️ Potential issue | 🟠 MajorEnforce (or document) MCP vs Gemini behavior.
README’s “OpenAI Responses API models only” claim matches the implementation:
mcpConnectorsare only added to the request insrc/code.gs’s_buildOpenAIPayload()(payload.tools.push(connector._toJson())), while_buildGeminiPayload()never includesmcpConnectors. There’s also no runtime error/guard when MCP connectors are used withmodel.includes("gemini")—so Gemini calls will just omit MCP. Add a check inaddMCP()/Chat.run()to throw a clear error, or update the README to state that MCP connectors won’t be sent/used with Gemini models.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` at line 280, The README and implementation mismatch: mcpConnectors are only serialized in _buildOpenAIPayload() and omitted by _buildGeminiPayload(), so add a runtime guard to fail fast when MCP connectors are present but a Gemini model is selected—modify addMCP() or Chat.run() to detect model.includes("gemini") (or equivalent model selection logic) and throw a clear, user-facing error stating that MCP connectors are unsupported with Gemini models; alternatively, if you prefer docs-only, update the README statement to explicitly state that MCP connectors will be ignored for Gemini models and no runtime error is thrown. Ensure you reference mcpConnectors, addMCP(), Chat.run(), _buildOpenAIPayload(), and _buildGeminiPayload() when making the change so reviewers can find the logic to update.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@README.md`:
- Around line 413-418: The README lists ConnectorObject methods (setLabel,
setDescription, setServerUrl, setConnectorId, setAuthorization,
setRequireApproval) and enum values that are not present in the src/ codebase;
either implement those methods on the ConnectorObject/class used in the codebase
(create methods with the exact names and signatures, e.g., setLabel(label:
string), setConnectorId(connectorId: 'gmail' | 'calendar' | 'drive'),
setRequireApproval(mode: 'never' | 'domain' | 'always'), etc.), or update the
README to match the actual API surface (rename the documented methods/enum
values to the real method names in the ConnectorObject implementation). Locate
the ConnectorObject class/function in the repo and ensure its public API matches
the README, or synchronously change the README to reflect the implemented method
names and allowed values.
- Line 280: The README and implementation mismatch: mcpConnectors are only
serialized in _buildOpenAIPayload() and omitted by _buildGeminiPayload(), so add
a runtime guard to fail fast when MCP connectors are present but a Gemini model
is selected—modify addMCP() or Chat.run() to detect model.includes("gemini") (or
equivalent model selection logic) and throw a clear, user-facing error stating
that MCP connectors are unsupported with Gemini models; alternatively, if you
prefer docs-only, update the README statement to explicitly state that MCP
connectors will be ignored for Gemini models and no runtime error is thrown.
Ensure you reference mcpConnectors, addMCP(), Chat.run(), _buildOpenAIPayload(),
and _buildGeminiPayload() when making the change so reviewers can find the logic
to update.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6ca0cda8-18c2-4cbe-b20a-52962c353e96
📒 Files selected for processing (1)
README.md
📜 Review details
🔇 Additional comments (6)
README.md (6)
119-120: LGTM!
272-272: LGTM!
298-299: LGTM!
1-431: LGTM!
247-248: Fix the “Google Workspace Native MCP Requirements” wording to align with Google docs.The MCP server URLs
https://drivemcp.googleapis.com/mcp/v1(Drive) andhttps://calendarmcp.googleapis.com/mcp/v1(Calendar) are official Google-provided MCP endpoints, and Google’s setup guidance requires enabling the corresponding MCP services (drivemcp.googleapis.com/calendarmcp.googleapis.com) in the GCP project. The “Standard Google Cloud Project” phrasing isn’t explicitly substantiated by the checked sources, so align that wording with the specific Google Cloud project/type requirement in the configuration docs.
391-392: ConfirmFunctionObject.endWithResult(bool)andFunctionObject.onlyReturnArguments(bool)are implemented
src/code.gsdefinesFunctionObject.endWithResult(bool)(setsendingFunction) andFunctionObject.onlyReturnArguments(bool)(setsonlyArgs), matching the README signatures atREADME.mdlines 391-392.- Tool-call handling uses these flags to implement the documented behavior:
onlyReturnArgumentsshort-circuits and returns only the tool-call arguments, whileendWithResultstops further AI calls after the tool execution (Gemini + OpenAI paths).
Motivation
Description
samples/directory containing self-contained Apps Script examples such assimple-chat.gs,system-prompts.gs,multi-model-usage.gs,function-calling-basics.gs,function-calling-advanced.gs,web-browsing.gs,image-analysis.gs,document-analysis.gs,knowledge-links.gs,vector-store-rag.gs,mcp-connectors.gs,conversation-continuation.gs,vertex-ai-setup.gs,configuration-options.gs, andsheets-ai-assistant.gsthat follow a consistent header + minimal runnable code pattern.Purpose,Use case,Required config, andExpected output, followed by a tiny example that exercises exactly one scenario usingGenAIAppAPIs.onlyReturnArguments(true)andendWithResult(true), and the basic sample function name was adjusted tosampleGetWeatherto avoid naming collisions in examples.newVectorStore(),newConnector(),enableBrowsing(),addImage(),addFile(),addKnowledgeLink(), and how to read/write from a Sheet withSpreadsheetApp.Testing
.gsfile by copying it to a temporary.jsand runningnode --checkon the copies, and all files passed the syntax check.wc/listing) as part of the automated verification steps.Codex Task