Skip to content

Gemini provider implementation and CLAUDE.md compliance fixes#4

Merged
arberx merged 2 commits intomainfrom
arberx/gemini-api-impl
Mar 9, 2026
Merged

Gemini provider implementation and CLAUDE.md compliance fixes#4
arberx merged 2 commits intomainfrom
arberx/gemini-api-impl

Conversation

@arberx
Copy link
Copy Markdown
Member

@arberx arberx commented Mar 9, 2026

Summary

Implements real Gemini API integration with model configurability throughout the stack, exposing grounding sources and search queries end-to-end. Adds GET /settings API endpoint and canonry settings CLI command for surface parity. Fixes eight CLAUDE.md compliance violations: deduplicated GroundingSource type to single contracts definition, thinned API handlers, fixed brand-name false positives with word boundaries, improved quota policy handling, deduplicated citation counts, and made grounding tool selection robust.

Test plan

  • TypeCheck passes across all packages (tsc --noEmit)
  • Gemini provider normalizeResult extracts answer text, domains, grounding sources, and search queries correctly
  • API route parseSnapshotRawResponse helper extracts typed fields from stored JSON
  • JobRunner accepts and uses geminiQuota from config; defaults to hardcoded values if not provided
  • Competitor pressure labels computed from unique cited keyword counts, not raw snapshot counts
  • Brand-name overlap detection uses word boundaries, preventing false positives
  • Grounding tool selection defaults to googleSearch, only uses deprecated googleSearchRetrieval for known legacy models
  • canonry settings command displays provider name/model and quota settings

🤖 Generated with Claude Code

arberx and others added 2 commits March 9, 2026 18:08
This commit completes Phase 2 implementation with real Gemini API calls, model configurability throughout the stack, and end-to-end grounding/search data visibility. Also fixes CLAUDE.md compliance violations: deduplicated GroundingSource type to single contracts definition, thinned API handlers, added missing CLI command for settings, fixed brand-name false positives, improved quota policy handling, and made grounding tool selection robust.

Key changes:
- Real executeTrackedQuery/healthcheck using Google Generative AI SDK with configurable grounding tool selection
- Model configurability: GeminiConfig, init prompt, server wiring to API and JobRunner
- Grounding sources and search queries stored in DB and exposed via /runs/:id endpoint
- New GET /settings API endpoint and canonry settings CLI command
- appendKeywords API call for non-destructive keyword addition
- Competitor pressure labels derived from citation coverage ratios
- Error formatting for human-readable Google API error messages
- Provider tests rewritten: normalizeResult unit tests replace live API tests
- CLAUDE.md fixes: GroundingSource deduplicated, API handler extraction, geminiQuota passed to JobRunner, citedKeywords deduplicated, brand-name regex with word boundaries, version-string heuristic replaced with legacy model list

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…e undercount, drawer race

- normalize.ts: use typed GoogleSearchRetrievalTool from @google/generative-ai for all
  models; removes bogus googleSearch shape and unsafe cast that hid the contract mismatch
- job-runner.ts: enforce quota policy at dispatch time — pre-flight daily budget check
  against usageCounters throws before any requests are made; sliding-window rate limiter
  delays between keywords to stay within maxRequestsPerMinute
- build-dashboard.ts: computeCompetitorPressure now checks snap.competitorOverlap instead
  of snap.citedDomains, matching the per-competitor table and counting subdomain citations
- App.tsx: openRun guards setRunDetail with a drawerState check so stale responses from
  abandoned fetches are discarded instead of overwriting the current selection

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@arberx arberx merged commit e6db3e5 into main Mar 9, 2026
1 check passed
@arberx arberx deleted the arberx/gemini-api-impl branch March 9, 2026 22:44
arberx added a commit that referenced this pull request Mar 16, 2026
… layer

Create AgentServices class that provides direct DB access for agent tools,
eliminating the circular dependency where tools called the server's own HTTP API.

Most read-only tools (get_status, get_evidence, get_timeline, list_keywords,
list_competitors, get_run_details) now use direct DB calls via AgentServices.

Write operations (run_sweep) and external integrations (GSC) still use HTTP
for proper job orchestration and auth handling.

Benefits:
- Eliminates ~1-5ms HTTP localhost roundtrip per tool call
- Removes startup timing dependency
- Simplifies auth config

Addresses review comment #4 (Architecture)
arberx added a commit that referenced this pull request Mar 16, 2026
… layer

Create AgentServices class that provides direct DB access for agent tools,
eliminating the circular dependency where tools called the server's own HTTP API.

Most read-only tools (get_status, get_evidence, get_timeline, list_keywords,
list_competitors, get_run_details) now use direct DB calls via AgentServices.

Write operations (run_sweep) and external integrations (GSC) still use HTTP
for proper job orchestration and auth handling.

Benefits:
- Eliminates ~1-5ms HTTP localhost roundtrip per tool call
- Removes startup timing dependency
- Simplifies auth config

Addresses review comment #4 (Architecture)
arberx added a commit that referenced this pull request Mar 16, 2026
… layer

Create AgentServices class that provides direct DB access for agent tools,
eliminating the circular dependency where tools called the server's own HTTP API.

Most read-only tools (get_status, get_evidence, get_timeline, list_keywords,
list_competitors, get_run_details) now use direct DB calls via AgentServices.

Write operations (run_sweep) and external integrations (GSC) still use HTTP
for proper job orchestration and auth handling.

Benefits:
- Eliminates ~1-5ms HTTP localhost roundtrip per tool call
- Removes startup timing dependency
- Simplifies auth config

Addresses review comment #4 (Architecture)
arberx added a commit that referenced this pull request Mar 17, 2026
… layer

Create AgentServices class that provides direct DB access for agent tools,
eliminating the circular dependency where tools called the server's own HTTP API.

Most read-only tools (get_status, get_evidence, get_timeline, list_keywords,
list_competitors, get_run_details) now use direct DB calls via AgentServices.

Write operations (run_sweep) and external integrations (GSC) still use HTTP
for proper job orchestration and auth handling.

Benefits:
- Eliminates ~1-5ms HTTP localhost roundtrip per tool call
- Removes startup timing dependency
- Simplifies auth config

Addresses review comment #4 (Architecture)
arberx added a commit that referenced this pull request Mar 17, 2026
… layer

Create AgentServices class that provides direct DB access for agent tools,
eliminating the circular dependency where tools called the server's own HTTP API.

Most read-only tools (get_status, get_evidence, get_timeline, list_keywords,
list_competitors, get_run_details) now use direct DB calls via AgentServices.

Write operations (run_sweep) and external integrations (GSC) still use HTTP
for proper job orchestration and auth handling.

Benefits:
- Eliminates ~1-5ms HTTP localhost roundtrip per tool call
- Removes startup timing dependency
- Simplifies auth config

Addresses review comment #4 (Architecture)
arberx added a commit that referenced this pull request Mar 17, 2026
… layer

Create AgentServices class that provides direct DB access for agent tools,
eliminating the circular dependency where tools called the server's own HTTP API.

Most read-only tools (get_status, get_evidence, get_timeline, list_keywords,
list_competitors, get_run_details) now use direct DB calls via AgentServices.

Write operations (run_sweep) and external integrations (GSC) still use HTTP
for proper job orchestration and auth handling.

Benefits:
- Eliminates ~1-5ms HTTP localhost roundtrip per tool call
- Removes startup timing dependency
- Simplifies auth config

Addresses review comment #4 (Architecture)
arberx added a commit that referenced this pull request Mar 18, 2026
Issue #1 — trailing-slash mismatch on root route:
  Register both '/canonry/' and '/canonry' (bare) variants so
  either URL shape returns the SPA without a 404.

Issue #2 — SPA fallback over-broad scope:
  When basePath is set, only serve index.html for paths that
  start with basePath; return JSON 404 for everything else so
  co-hosted apps on the same origin are not hijacked.

Issue #3 — bare '/' base path causing duplicate-route error:
  Normalised base path equal to '/' is now treated as undefined
  (no base path), keeping the fastify-static prefix at '/' and
  avoiding a duplicate route registration error.

Issue #4 — routePrefix without leading slash silently mis-routes:
  Validate opts.routePrefix at startup and throw a descriptive
  error if it does not start with '/'.

Issue #5 — copy-pasted health handler body:
  Extract to a shared healthHandler const; both /health and
  ${basePath}health now reference the same function.
arberx added a commit that referenced this pull request Mar 18, 2026
* fix: base-path-aware API route prefix and SPA fallback

When `--base-path /canonry/` is set, three things were broken:

1. API routes were registered at /api/v1 regardless of base path,
   so requests to /canonry/api/v1/* had no matching route.
2. setNotFoundHandler checked request.url.startsWith('/api/') —
   correct without base path, but missed /canonry/api/v1/* URLs,
   causing the SPA catch-all to return 200 HTML for all API routes.
3. @fastify/static and root route handler were prefix-unaware,
   so static assets and the root index.html were not served under
   the configured base path.

Fix:
- Add `routePrefix` option to ApiRoutesOptions (named to avoid
  collision with Fastify's reserved `prefix` register option).
- Compute basePath once before apiRoutes registration and use it
  to set routePrefix = `${basePath}api/v1` or '/api/v1' default.
- Register @fastify/static and root handler at `basePath ?? '/'`.
- Update setNotFoundHandler guard to check both '/api/' and
  '${basePath}api/' so it works with and without --base-path.
- Register /health at both '/health' and '${basePath}health'.

Closes #113

* fix: address review feedback on base-path routing

Issue #1 — trailing-slash mismatch on root route:
  Register both '/canonry/' and '/canonry' (bare) variants so
  either URL shape returns the SPA without a 404.

Issue #2 — SPA fallback over-broad scope:
  When basePath is set, only serve index.html for paths that
  start with basePath; return JSON 404 for everything else so
  co-hosted apps on the same origin are not hijacked.

Issue #3 — bare '/' base path causing duplicate-route error:
  Normalised base path equal to '/' is now treated as undefined
  (no base path), keeping the fastify-static prefix at '/' and
  avoiding a duplicate route registration error.

Issue #4 — routePrefix without leading slash silently mis-routes:
  Validate opts.routePrefix at startup and throw a descriptive
  error if it does not start with '/'.

Issue #5 — copy-pasted health handler body:
  Extract to a shared healthHandler const; both /health and
  ${basePath}health now reference the same function.

---------

Co-authored-by: Claw (AINYC Agent) <agent@ainyc.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant