Skip to content

Conversation

@GuillemineA
Copy link
Collaborator

Summary

  • expand runTestAcrossModels helper to allow post-run assertions
  • add tests for file attachments, metadata handling, response ID tracking, and vector store lifecycle
  • fix vision test by removing call to non-existent enableVision method

Testing

  • npm test (fails: Could not read package.json)

https://chatgpt.com/codex/tasks/task_b_689c3e2f1bb0832f9bfdf6cc354ae817

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 13, 2025

📝 Walkthrough

Summary by CodeRabbit

  • Tests
    • Expanded coverage with new scenarios for file attachments, metadata/logging behavior, response ID continuity, and vector store lifecycle.
    • Introduced a centralized cross-model test runner to validate behavior consistently across multiple models.
    • Updated vision test to describe images without an explicit enable step.
  • Refactor
    • Streamlined test harness to support post-run hooks and per-model execution, improving maintainability and extensibility of the test suite.

Walkthrough

Refactors the test harness to iterate across multiple models with an optional afterRun hook, removes explicit vision enabling, and adds four tests for file attachment, metadata/log logging, response ID tracking, and vector store lifecycle using blob utilities.

Changes

Cohort / File(s) Summary
Test harness and new cross-model tests
src/testFunctions.gs
Added tests: testAddFile, testMetadataAndLogs, testResponseIdTracking, testVectorStoreLifecycle. Updated runTestAcrossModels to accept afterRun and iterate over GPT_MODEL, REASONING_MODEL, GEMINI_MODEL. Modified testVision to skip enableVision(true). Introduced Utilities.newBlob usage and vector store lifecycle operations.

Sequence Diagram(s)

sequenceDiagram
  participant Runner as runTestAcrossModels
  participant Model as Model (GPT/Reasoning/Gemini)
  participant Chat as Chat
  participant After as afterRun (optional)

  Runner->>Model: for each model
  Runner->>Chat: create chat for model
  Chat->>Model: run(test setup/options)
  Model-->>Chat: response
  Chat-->>Runner: response
  alt afterRun provided
    Runner->>After: afterRun(chat, response, model)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/add-missing-tests-to-testfunctions.gs

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🔭 Outside diff range comments (1)
src/testFunctions.gs (1)

23-44: Bug: runOptions can override the per-iteration model. Also, isolate per-model failures so one failure doesn’t stop the batch.

Because { model: model.name, ...runOptions } puts runOptions last, any caller-provided runOptions.model will silently override the model under test. Reverse the merge order and add per-model try/catch to keep the runner resilient.

Apply this diff:

   models.forEach(model => {
-    const chat = GenAIApp.newChat();
-    setupFunction(chat);
-    const options = { model: model.name, ...runOptions };
-    const response = chat.run(options);
-    console.log(`${testName} ${model.label}:\n${response}`);
-    if (afterRun) {
-      afterRun(chat, response, model);
-    }
+    try {
+      const chat = GenAIApp.newChat();
+      setupFunction(chat);
+      const options = { ...runOptions, model: model.name }; // ensure the loop's model wins
+      const response = chat.run(options);
+      console.log(`${testName} ${model.label}:\n${response}`);
+      if (afterRun) {
+        afterRun(chat, response, model);
+      }
+    } catch (err) {
+      console.error(`Error running "${testName}" for ${model.label}: ${err && err.stack || err}`);
+    }
   });

Optional: Consider setting API keys once (e.g., in testAll) to avoid repeated calls in every runTestAcrossModels invocation.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6262f53 and 3414fd7.

📒 Files selected for processing (1)
  • src/testFunctions.gs (3 hunks)
🔇 Additional comments (1)
src/testFunctions.gs (1)

137-144: Verify addFile support across all models or gate the test per capability.

Attaching files may not be supported uniformly (e.g., some model backends may not accept file blobs). If unsupported, this will fail that iteration and abort the rest unless the runner is hardened.

Would you like me to add a capability check and skip the model(s) that don’t support addFile?

Comment on lines +169 to +191
function testResponseIdTracking() {
GenAIApp.setGeminiAPIKey(GEMINI_API_KEY);
GenAIApp.setOpenAIAPIKey(OPEN_AI_API_KEY);

const models = [
{ name: GPT_MODEL, label: "GPT" },
{ name: REASONING_MODEL, label: "reasoning" },
{ name: GEMINI_MODEL, label: "gemini" }
];

models.forEach(model => {
const chat = GenAIApp.newChat();
chat.addMessage("Hello");
chat.run({ model: model.name });
const lastId = chat.retrieveLastResponseId();
chat.addMessage("Continue this conversation.");
if (lastId) {
chat.setPreviousResponseId(lastId);
}
const response = chat.run({ model: model.name });
console.log(`Response ID test ${model.label}:\n${response}`);
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Harden the response ID test: log the retrieved ID and isolate per-model failures.

This reduces flakiness, surfaces whether an ID was retrieved, and prevents one failure from aborting subsequent iterations. Also, API keys are redundantly set elsewhere; ideally centralize.

Apply this diff:

-  models.forEach(model => {
-    const chat = GenAIApp.newChat();
-    chat.addMessage("Hello");
-    chat.run({ model: model.name });
-    const lastId = chat.retrieveLastResponseId();
-    chat.addMessage("Continue this conversation.");
-    if (lastId) {
-      chat.setPreviousResponseId(lastId);
-    }
-    const response = chat.run({ model: model.name });
-    console.log(`Response ID test ${model.label}:\n${response}`);
-  });
+  models.forEach(model => {
+    try {
+      const chat = GenAIApp.newChat();
+      chat.addMessage("Hello");
+      chat.run({ model: model.name });
+      const lastId = chat.retrieveLastResponseId();
+      console.log(`Last response id for ${model.label}: ${lastId || 'n/a'}`);
+      chat.addMessage("Continue this conversation.");
+      if (lastId) {
+        chat.setPreviousResponseId(lastId);
+      } else {
+        console.warn(`No response id retrieved for ${model.label}; running without previous id`);
+      }
+      const response = chat.run({ model: model.name });
+      console.log(`Response ID test ${model.label}:\n${response}`);
+    } catch (err) {
+      console.error(`Response ID test failed for ${model.label}: ${err && err.stack || err}`);
+    }
+  });

Please confirm that retrieveLastResponseId/setPreviousResponseId are implemented for all three models; if not, we should feature-detect and skip unsupported models.


🏁 Script executed:

#!/bin/bash
# Search for retrieveLastResponseId and setPreviousResponseId definitions across .gs files
rg -n --glob '*.gs' 'retrieveLastResponseId'
rg -n --glob '*.gs' 'setPreviousResponseId'

Length of output: 379


🏁 Script executed:

#!/bin/bash
# Display implementation of retrieveLastResponseId and setPreviousResponseId in code.gs
sed -n '300,360p' src/code.gs

Length of output: 1871


Harden the response ID test and confirm ID methods exist

I’ve verified that retrieveLastResponseId and setPreviousResponseId are implemented on the Chat object, so no per-model feature detection is needed. Applying the below diff will:

  • Log the retrieved ID (or warn if missing)
  • Isolate failures per model to avoid aborting the loop
  • Centralize error handling with try/catch

Also, consider centralizing API-key setup in your test harness instead of setting them in each test.

Apply this diff in src/testFunctions.gs (lines 169–191):

-  models.forEach(model => {
-    const chat = GenAIApp.newChat();
-    chat.addMessage("Hello");
-    chat.run({ model: model.name });
-    const lastId = chat.retrieveLastResponseId();
-    chat.addMessage("Continue this conversation.");
-    if (lastId) {
-      chat.setPreviousResponseId(lastId);
-    }
-    const response = chat.run({ model: model.name });
-    console.log(`Response ID test ${model.label}:\n${response}`);
-  });
+  models.forEach(model => {
+    try {
+      const chat = GenAIApp.newChat();
+      chat.addMessage("Hello");
+      chat.run({ model: model.name });
+      const lastId = chat.retrieveLastResponseId();
+      console.log(`Last response id for ${model.label}: ${lastId || 'n/a'}`);
+      chat.addMessage("Continue this conversation.");
+      if (lastId) {
+        chat.setPreviousResponseId(lastId);
+      } else {
+        console.warn(`No response id retrieved for ${model.label}; running without previous id`);
+      }
+      const response = chat.run({ model: model.name });
+      console.log(`Response ID test ${model.label}:\n${response}`);
+    } catch (err) {
+      console.error(`Response ID test failed for ${model.label}: ${err.stack || err}`);
+    }
+  });
🤖 Prompt for AI Agents
In src/testFunctions.gs around lines 169 to 191, the response ID test should be
hardened: wrap each model iteration in a try/catch so one model failure doesn't
abort the loop; after first run capture the ID and log it (or console.warn if
missing) before calling setPreviousResponseId; ensure setPreviousResponseId is
only called when an ID exists; and log per-model errors inside the catch so
failures are isolated and informative; also consider moving the API-key setup
out of this test into shared test harness rather than setting keys here.

Comment on lines +193 to +210
function testVectorStoreLifecycle() {
GenAIApp.setOpenAIAPIKey(OPEN_AI_API_KEY);
const blob = Utilities.newBlob("Vector store content", "text/plain", "vs.txt");

const store = GenAIApp.newVectorStore()
.setName("test-store-" + Date.now())
.setDescription("Temporary store for tests")
.createVectorStore();

const storeId = store.getId();
const fileId = store.uploadAndAttachFile(blob, { source: "test" });
const files = store.listFiles();
console.log(`Vector store files: ${JSON.stringify(files)}`);

store.deleteFile(fileId);
store.deleteVectorStore();
console.log(`Vector store ${storeId} cleaned up.`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Prevent resource leaks in vector store tests; add try/finally and brief wait for eventual consistency.

If any step throws, the vector store won’t be deleted, leaving orphaned resources. Also, a short delay before listing files can reduce flakiness while the backend indexes the upload.

Apply this diff:

-  const store = GenAIApp.newVectorStore()
-    .setName("test-store-" + Date.now())
-    .setDescription("Temporary store for tests")
-    .createVectorStore();
-
-  const storeId = store.getId();
-  const fileId = store.uploadAndAttachFile(blob, { source: "test" });
-  const files = store.listFiles();
-  console.log(`Vector store files: ${JSON.stringify(files)}`);
-
-  store.deleteFile(fileId);
-  store.deleteVectorStore();
-  console.log(`Vector store ${storeId} cleaned up.`);
+  const store = GenAIApp.newVectorStore()
+    .setName("test-store-" + Date.now())
+    .setDescription("Temporary store for tests")
+    .createVectorStore();
+
+  const storeId = store.getId();
+  let fileId;
+  try {
+    fileId = store.uploadAndAttachFile(blob, { source: "test" });
+    // Brief wait for indexing/consistency if backend is eventually consistent
+    Utilities.sleep(1500);
+    const files = store.listFiles();
+    console.log(`Vector store files: ${JSON.stringify(files)}`);
+    if (fileId) {
+      store.deleteFile(fileId);
+    }
+  } finally {
+    store.deleteVectorStore();
+    console.log(`Vector store ${storeId} cleaned up.`);
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function testVectorStoreLifecycle() {
GenAIApp.setOpenAIAPIKey(OPEN_AI_API_KEY);
const blob = Utilities.newBlob("Vector store content", "text/plain", "vs.txt");
const store = GenAIApp.newVectorStore()
.setName("test-store-" + Date.now())
.setDescription("Temporary store for tests")
.createVectorStore();
const storeId = store.getId();
const fileId = store.uploadAndAttachFile(blob, { source: "test" });
const files = store.listFiles();
console.log(`Vector store files: ${JSON.stringify(files)}`);
store.deleteFile(fileId);
store.deleteVectorStore();
console.log(`Vector store ${storeId} cleaned up.`);
}
function testVectorStoreLifecycle() {
GenAIApp.setOpenAIAPIKey(OPEN_AI_API_KEY);
const blob = Utilities.newBlob("Vector store content", "text/plain", "vs.txt");
const store = GenAIApp.newVectorStore()
.setName("test-store-" + Date.now())
.setDescription("Temporary store for tests")
.createVectorStore();
const storeId = store.getId();
let fileId;
try {
fileId = store.uploadAndAttachFile(blob, { source: "test" });
// Brief wait for indexing/consistency if backend is eventually consistent
Utilities.sleep(1500);
const files = store.listFiles();
console.log(`Vector store files: ${JSON.stringify(files)}`);
if (fileId) {
store.deleteFile(fileId);
}
} finally {
store.deleteVectorStore();
console.log(`Vector store ${storeId} cleaned up.`);
}
}
🤖 Prompt for AI Agents
In src/testFunctions.gs around lines 193 to 210, the test currently uploads a
file and deletes the vector store without protection against exceptions and
without a short wait for eventual indexing; wrap the upload/list/delete
lifecycle in a try/finally so the file and the vector store are always removed
even if an intermediate step throws, and insert a brief sleep (e.g., a few
hundred milliseconds) after upload before listing files to reduce flakiness from
eventual consistency; ensure you capture the returned fileId so the finally
block can safely delete the file (guarding deletion calls if ids are undefined)
and still delete the store in all cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants