Gemini provider implementation and CLAUDE.md compliance fixes#4
Merged
Conversation
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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
🤖 Generated with Claude Code