Skip to content

Detection: Python AI SDK clients (google.genai / google.generativeai) unmapped + clients built in with/function scope untracked #143

Description

@AndresL230

Part of #142.

Summary

Python SDK client calls to Google Gemini are not detected. In sapling, services/gemini_service.py:74_client.models.generate_content(...) (the google.genai SDK) — produced zero endpoints; the entire Gemini-backed backend scanned as 0 external calls.

Root cause

  1. PACKAGE_TO_PROVIDER (src/ast/ast-scanner.ts:98-114) and CLASS_TO_PACKAGE (src/ast/import-resolver.ts:47-73) are JS-centric. The Python Google-AI packages — google.genai (new from google import genaigenai.Client()) and google.generativeai — have no entry. processPythonAssignment (import-resolver.ts:497) resolves _client = genai.Client() to package "google" (the import segment); "google" maps to no provider, so resolveProvider yields provider "google", no fingerprint matches, and the gate at core-scanner.ts:269 drops it.
  2. Even with the mapping, client-var binding only happens for top-level assignments. Clients created inside a function body or async with httpx.AsyncClient() as client: / with genai.Client() as c: are never recorded — buildExtendedMaps (ast-scanner.ts:315) and resolveImportsCore (import-resolver.ts:531) only walk top-level tree.rootNode statements.

Proposed fix

  • Add Python AI packages to the package→provider map: google.genai / google.generativeaigemini; confirm openai, anthropic, cohere, mistralai Python roots resolve. Add the genai.Client / genai.GenerativeModel constructor names to CLASS_TO_PACKAGE.
  • Track client-var assignments in nested scopes (function bodies, with / async with aliases), not just module top-level.
  • Ensure the registry has the SDK method chains: lookupMethod("gemini", "models.generate_content" | "models.generateContent" | "GenerativeModel.generate_content"). gemini.json already has the REST endpoints; add the SDK chains.

Evidence

node dist/cli/scan.js /path/to/sapling/backend --format json → 215 endpoints, all provider:internal, 0 Gemini. Manual scan found ~26 Gemini sites incl. services/gemini_service.py:74, services/flashcard_import_service.py:240/251/259/266, services/course_context_service.py:56.

Acceptance criteria

  • _client = genai.Client(); _client.models.generate_content(...) resolves to provider gemini.
  • A client constructed inside a function or with block is attributed.
  • Re-scan of sapling/backend surfaces the gemini_service + flashcard_import_service Gemini calls.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/detectiondocs/accuracy/detection.md — finding every call site, attributing correctlybugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions