Commit graph

210 commits

Author SHA1 Message Date
Vadym Samoilenko
3caf4ec5f6 fix(gemini): update fallback model to gemini-3.1-flash-lite 2026-05-18 13:12:49 +01:00
Vadym Samoilenko
1982d5d76e feat(knowledge-base): smart resume for interrupted processing jobs
On server restart, stale active jobs are automatically resumed rather
than failed. Docs already parsed in a prior run are skipped (resume from
cache), docs stuck at 'parsing' are reset to 'pending' and re-parsed.

- Repository: add get_all_stale_active_jobs() and reset_stuck_parsing_docs()
- Service: skip already-parsed docs in _parse_doc(), reset stuck docs on start
- Main: recover stale jobs via asyncio.create_task() in lifespan startup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 10:20:35 +01:00
Vadym Samoilenko
a40e3d4052 Fix support email: correct Mailgun credentials in .env.deploy.example
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 17:26:28 +01:00
Vadym Samoilenko
c948b34f5f Fix support email: update Mailgun credentials in .env.deploy.example
Correct domain (mg.oliver.solutions), API key, and from address so
support questions from the Profile page actually deliver.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 16:47:26 +01:00
Vadym Samoilenko
41ea5dc57b Update Workfront Campaign ID field: simplify placeholder and remove format validation
- Change placeholder from '#WF_12345' to 'WF1234567'
- Remove format validation and error messaging (field is optional, free-form)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 15:54:27 +01:00
Vadym Samoilenko
71639030ba Fix 500 error on knowledge base Process Documents
knowledge_base_service and analysis_service were local variables inside
the lifespan() function — not module-level exports. Importing them via
'from app.main import ...' always failed with ImportError → 500.

Use request.app.state (same pattern as analysis_routes.py) instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 15:50:36 +01:00
Vadym Samoilenko
aeab7d3b18 Rename Legal Agent to Risk & Control Agent across frontend and backend
Updates all display labels (PDF report, campaign page, Knowledge Base card, analytics, status dashboard, checks overview) and aligns internal agent name in backend. Adds migration 010 to update the knowledge base display_name in production DB.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 15:10:32 +01:00
Vadym Samoilenko
2ebaf6420f Add deploy-dev.sh for dev server (sudo docker, fix dist permissions)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 10:57:48 +01:00
Vadym Samoilenko
194f57f302 Replace logo SVG with PNG v6 in Sidebar and PDF Report
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 10:50:53 +01:00
Vadym Samoilenko
3f0e774ccb Replace logo with v6 SVG across Sidebar and PDF Report
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 13:27:51 +01:00
Vadym Samoilenko
a304078a11 Fix CSV export: use correct agent_review JSON keys for RAG columns
legalAgentReview, brandAgentReview, channelBestPracticesAgentReview,
channelTechSpecsAgentReview, and leadAgentSummary are the actual keys
stored in the JSONB column — not legalAgent, brandAgent, channelAgent.*,
and leadAgent.summary which were causing empty CSV values.
2026-03-19 12:23:47 +00:00
Vadym Samoilenko
447c4b2a95 Add CSV export of campaign data for super_admin and oversight_admin
Adds a server-side CSV export covering all campaign, proof, and version
data including agent RAG statuses. The export respects the active agency
filter so oversight admins can scope the download to a single agency.

- backend: `CampaignRepository.get_export_rows()` — flat join across
  Campaign → Proof → ProofVersion with Agency and User, extracts agent
  RAG statuses from the `agent_review` JSONB column
- backend: `GET /api/export/campaigns-csv` endpoint gated to
  super_admin / oversight_admin, streams a dated CSV file
- frontend: `apiService.downloadCampaignsCsv(agencyId?)` — fetches blob
  and triggers browser download
- frontend: threads `selectedAgencyId` prop from App → Campaigns →
  CampaignList so the export uses the active filter
- frontend: Export CSV button in CampaignList header, visible only to
  super_admin / oversight_admin, with spinner while downloading

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 11:35:24 +00:00
Vadym Samoilenko
4e6545e5f2 Switch primary model to Pro, Flash as fallback
Now that REST polling removes the 30s GCP LB timeout constraint,
gemini-3.1-pro-preview is restored as primary and gemini-3-flash-preview
is used only when Pro fails or times out.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 15:37:56 +00:00
Vadym Samoilenko
a6fc149788 Replace WebSocket with REST polling to fix GCP LB 30s timeout
POST /api/analyze submits an analysis job and returns job_id instantly.
GET /api/analyze/{job_id} returns progress + result; frontend polls every 2s.

Analysis runs as asyncio.create_task in the background — each HTTP request
completes in milliseconds, well within the 30s GCP Load Balancer limit.

- Add backend/app/services/job_store.py: in-memory AnalysisJob store with
  30-min TTL cleanup
- Add backend/app/api/analysis_routes.py: POST + GET /api/analyze endpoints
  with full analysis pipeline (hash check, DB persistence, PDF pages, etc.)
- Remove backend/app/websocket/: handlers.py, manager.py, __init__.py
- Update backend/app/main.py: wire analysis_router, store analysis_service
  in app.state, drop all WebSocket imports and endpoint
- Update frontend/services/geminiService.ts: replace WS with fetch+poll;
  function signatures unchanged so App.tsx / WIPReviewer.tsx need no edits
- Remove VITE_BACKEND_WS_URL from vite.config.ts, deploy.sh, .env.deploy.example
- Update cloudrun.yaml: remove WebSocket-specific session affinity annotation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 15:26:01 +00:00
Vadym Samoilenko
1de572fcb0 Switch primary model to flash to fix GCP LB 30s timeout
gemini-3.1-pro-preview takes ~25s per call, hitting the GCP load
balancer's 30s hard timeout before analysis completes. Flash model
returns in ~5-8s, fitting comfortably within the limit. Pro model
kept as fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 13:18:24 +00:00
Vadym Samoilenko
e85681b775 Fix WebSocket drops: add bidirectional keepalive pings
Frontend now sends client→server ping every 15s during analysis to keep
the GCP LB idle timeout alive from both directions. Backend responds
with pong. Previously only server→client heartbeats were sent, which
didn't reset the proxy's client-side idle timer.

Also updates favicon to Oliver brand mark (gold M).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 13:10:27 +00:00
Vadym Samoilenko
e98143de55 Fix favicon/CSS 404s; heartbeat 25s→10s already staged
- index.html: remove broken /index.css link (file never existed, noisy 404)
- index.html: fix favicon path to use %BASE_URL% so Vite rewrites it
  correctly for /modcomms/ subpath deployment
- public/favicon.svg: add minimal M favicon (was completely missing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 12:57:49 +00:00
Vadym Samoilenko
57cd8c5613 Reduce heartbeat interval 25s→10s to beat upstream proxy idle timeout
Upstream SSL terminator closes idle WS connections at ~26s. Heartbeat
at T+25 was racing with the close. 10s interval keeps the connection
alive through any proxy with up to ~20s idle timeout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 12:56:24 +00:00
Vadym Samoilenko
416c9dce0e Fix QC scroll, show error toasts, enable Apache WS module
- ProofDetailView: remove h-full from root div so content can scroll
  naturally (h-full was capping height at viewport, blocking scroll)
- App.tsx: wire up error state to a top toast banner so users see
  failures (campaign load, proof upload, etc.) instead of silent drops;
  auto-dismiss after 8s, same pattern as notification toast
- Apache: enabled mod_proxy_wstunnel (was missing — proxy_http was
  handling WebSocket connections and dropping them due to HTTP-level
  timeouts; wstunnel provides a proper bidirectional tunnel)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 12:52:30 +00:00
Vadym Samoilenko
5c338c31fb Fix WebSocket connection dropped during long proof analysis
- Add 25s heartbeat ping from backend to prevent Apache/proxy idle-timeout
  killing the connection during 1-3 min analysis runs
- Handle heartbeat silently in both analyzeProof and analyzeWIPProof frontend handlers
- Run PDF rasterization via asyncio.to_thread so heartbeats aren't blocked
- Wrap analyze_proof with asyncio.wait_for(timeout=300) for a hard 5-min cap
- Log dropped send_message calls in ConnectionManager instead of swallowing silently
- cloudrun.yaml: add sessionAffinity, startup probe, raise containerConcurrency 4→10,
  document DISABLE_AUTH option

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 11:23:59 +00:00
Vadym Samoilenko
ef1e4adabd Fix PDF logo URL to include Vite base path in production
window.location.origin alone gives https://baic.oliver.solutions, but the
app is deployed at /modcomms/ (VITE_BASE_PATH=/modcomms/), so the logo
was loading from the wrong path (404). Now uses:
  window.location.origin + import.meta.env.BASE_URL + filename
which resolves correctly in both dev (http://localhost:3000/...) and
production (https://baic.oliver.solutions/modcomms/...).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 14:11:12 +00:00
Vadym Samoilenko
f520aba397 Fix KB distillation fallback and SpecVersion type annotation
- knowledge_base_service.py: wrap Gemini distillation call in try/except
  to fall back to fallback_client/fallback_model if primary times out,
  matching the fallback behaviour in GeminiService._generate_content()

- models.py: fix SpecVersion.source_document_ids ORM type annotation from
  Mapped[Optional[dict]] to Mapped[Optional[list]] — the field stores a
  JSON array of document ID strings, not an object

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 14:03:25 +00:00
Vadym Samoilenko
060fbeba76 Fix GeminiService client attribute error in knowledge base distillation
Replace self.gemini.client with self.gemini.primary_client on line 295 of
knowledge_base_service.py. GeminiService only exposes primary_client and
fallback_client — there is no client attribute. This caused all processing
jobs to fail at the distillation step, which is also why Version History
was always blank (no SpecVersion records were ever created).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 13:59:59 +00:00
Vadym Samoilenko
538a32505e Fix LlamaParse 401 + update logo to v5
- Add LLAMA_CLOUD_BASE_URL config option so the LlamaCloud regional
  endpoint can be set without code changes (fixes 401/region errors
  on production); pass it through to AsyncLlamaCloud client init
- Document LLAMA_CLOUD_BASE_URL in .env.deploy.example with EU endpoint
- Copy BAR-ModComms-logo-v5.png to frontend/public
- Sidebar: update logo reference v4 → v5
- PDF header: update logo v4 → v5, wrap in black (#000) band for
  legibility, remove duplicate "Oliver" wordmark

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:22:31 +00:00
Vadym Samoilenko
da63629720 Auto-generate backend/.env and frontend/.env.local from .env.deploy
The deploy script now generates both env files automatically — no more
manual file creation on the server. All secrets and VITE_ vars are
centralised in .env.deploy (gitignored). Updated .env.deploy.example
with all required variables and inline documentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 11:57:17 +00:00
Vadym Samoilenko
ff1c809249 Prepare production deployment for baic.oliver.solutions/modcomms
- Add VITE_BASE_PATH support to vite.config.ts so assets resolve correctly under /modcomms/ subpath
- Fix home URL in urlState.ts to use BASE_URL instead of hardcoded '/'
- Fix sidebar logo src to use BASE_URL prefix (Vite doesn't rewrite TSX src attributes)
- Fix Azure AD redirect/logout URIs to include BASE_URL subpath in authConfig.ts and App.tsx
- Add migration 009 to remove Mindshare/Zenith and add Rapp agency
- Update .env.deploy.example with production values for baic.oliver.solutions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 11:54:00 +00:00
Vadym Samoilenko
a2382cf027 Fix PDF page breaks, badge alignment, and responsive layout
- PDFReport: Fix RagStatus badge padding (symmetric 4px top/bottom + lineHeight 1.2) so text is centered rather than floating at the top
- PDFReport: Add breakInside: 'avoid' to preview+summary grid, agent reviews grid, and li elements to prevent content being cut mid-sentence across PDF page breaks
- Campaigns: Lower two-column layout breakpoint from xl (1280px) to lg (1024px) so laptop screens show side-by-side proof detail view
- Campaigns: Add flex-wrap to button row so Download Proof / Download Report / New Version buttons wrap gracefully on smaller screens

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 13:17:26 +00:00
Vadym Samoilenko
fdb5a2d961 Fix PDF export: switch to browser print, fix page breaks and bullet alignment
- Replace html2canvas + jsPDF with window.print() in both handleExportPDF
  and handleDownloadReport — browser print properly respects CSS break-inside:
  avoid on agent cards and page-break-before on proof pages, eliminating
  orphaned section headings
- Add listStylePosition: 'outside' and explicit lineHeight to <ul>/<li>
  elements in PDFReport so bullet symbols sit at the text baseline
- Add pageBreakInside: 'avoid' alongside existing breakInside: 'avoid' on
  agent cards for cross-browser compatibility
- Replace placeholder shield icon and plain-text Oliver SVG on cover page
  with BAR-ModComms-logo-v4.png (Barclays eagle) and styled Oliver wordmark

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 13:06:12 +00:00
Vadym Samoilenko
13a3ff87cc Remove misleading size constraint from proof upload modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 12:56:43 +00:00
Vadym Samoilenko
4a2182ce2a Fix Proof Detail page responsive layout and button states
- Add min-w-[900px] to root container so content scrolls horizontally below 900px instead of being crushed
- Change grid breakpoint from lg to xl so 3-column layout only fires at 1280px
- Add min-w-0 + truncate to proof title to prevent clipping at narrow widths
- Add flex-wrap to buttons row so buttons wrap rather than overflow
- Add shrink-0/whitespace-nowrap to all action buttons to prevent compression
- Improve button interaction states with hover:shadow-sm, active:scale-95, and transition-all

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 12:54:55 +00:00
Vadym Samoilenko
1f2a2e5016 Settings: fix sub-channel dropdown and Add button styling
- Sub-Channel dropdown: always white bg + azure border (never azure fill),
  even when a value is selected; channel dropdown retains azure fill
- Add button: joined to input field as a single group (no gap, shared
  border, matching corner radius); button colour is azure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 16:10:10 +00:00
Vadym Samoilenko
f22b24eb8a Fix Settings dropdown disabled state and chevron colours
- Disabled sub-channel dropdown: was showing grey bg + grey border;
  now shows azure outline (opacity-50) consistent with unselected state
- Chevrons: now white when dropdown is azure-filled (selected),
  azure when unselected — previously always azure which was invisible
  against the azure background

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 16:06:19 +00:00
Vadym Samoilenko
2553d1f952 Fix logo proportions: use w-full h-auto instead of fixed height
h-28 w-auto was locking height which can distort aspect ratio in the
narrow sidebar. w-full h-auto scales proportionally from the container
width with object-contain as a safety net.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:56:12 +00:00
Vadym Samoilenko
dfb758fa61 Fix email resolution from Azure AD token claims
Azure AD v1 access tokens (sts.windows.net issuer) use the 'upn' claim
for the user principal name/email, not 'email' or 'preferred_username'.
Add 'upn' as a fallback so email is correctly resolved on login.

Also add debug logging to show which claims are present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:55:00 +00:00
Vadym Samoilenko
fa00a86777 Analytics AI summary: restore thick left sky accent border (border-l-8)
Thin border all around, prominent 8px left accent in oliver-sky colour
per design guidance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:51:14 +00:00
Vadym Samoilenko
d5eba4c6da Apply design feedback: dropdowns, analytics, sidebar, logo
- Settings: selected dropdown state now shows azure bg with white text
- Analytics stats: icon circle bg changed from white to grey (#EFEFEF)
- Analytics AI summary: uniform border (remove asymmetric left border);
  lightbulb icon sized to match other icons (h-9 w-9)
- Sidebar: active nav item highlight changed from azure to white,
  visually connecting to the white main content area
- Sidebar: logo increased from h-20 to h-28

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:49:31 +00:00
Vadym Samoilenko
c6f7b0d5f1 Populate email on login for users with empty email field
When a user already exists in the DB, get_or_create_from_azure was
returning early without updating their email from Azure AD claims.
Users created before email sync was in place would permanently show
empty emails in User Management.

Now syncs email from Azure AD claims on each login if the stored
email is empty.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 15:45:48 +00:00
Vadym Samoilenko
d7fd435210 Add IVU Testing & Performance Monitoring implementation plan
Standalone Python CLI tool plan for Barclays IVU Model compliance testing:
batch WebSocket analysis, AI-based scoring via Claude, consistency metrics,
per-run PDF reports, and comparative drift detection reports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:28:56 +00:00
Vadym Samoilenko
0432635153 Grant oversight_admin write access to campaigns and proofs
Oversight admins can now create campaigns, upload proofs, and
flag/resolve issues when they have an agency assigned. They retain
all existing cross-agency read access for analytics, auditing, and
user management. Oversight admins without an agency see a read-only
campaigns view.

Changes:
- Add oversight_admin to canWrite permission in UserContext
- Guard readOnly for oversight_admin without agency in App.tsx
- Remove oversight_admin block from require_write_access dependency
- Remove WebSocket oversight_admin upload block in main.py
- Require agency for oversight_admin campaign creation in routes.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:08:54 +00:00
Vadym Samoilenko
0348693ebd Increase sidebar logo size from h-12 to h-20
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:29:43 +00:00
Vadym Samoilenko
8317e01568 Add azure border to all modal containers per Oliver design
All modal inner containers now have border-2 border-oliver-azure
for consistent Oliver branding across:
- CreateCampaignModal, CreateProjectModal
- FeedbackReport (resolve + flag modals)
- UserManagement (confirmation + history modals)
- Campaigns (upload, delete confirmation, version history modals)
- Projects (upload, delete modals)
- Login (support contact modal)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:21:59 +00:00
Vadym Samoilenko
4302b9391a Restyle full application from Barclays to Oliver Agency brand
Replace entire Barclays colour palette (navy #1A2142, lime #C3FB5A, violet
#7A0FF9) with Oliver brand tokens: black #1A1A1A, gold #FFCB05, orange
#FF5C00, azure #0487B6, sky #5DF5EA, grey #EFEFEF, green #09821F.

- Switch font from Inter/Barclays Effra to Arial (system font)
- Add new Oliver logo asset (BAR-ModComms-logo-v4.png)
- Sidebar: black background, new logo, azure active state
- Hero: orange "Intelligent Review" text, hide AI-Powered tagline
- Hide ChecksOverview on Home page per Oliver design
- Toast notification: orange background with black text
- All tables: sky headers, alternating white/grey rows
- Campaign badges: gold "In Progress", green "Completed"
- Analytics: grey KPI cards, sky accent on Key Insight, oliver trend colours
- All buttons: azure fill, pill-shaped (rounded-full)
- All tabs/toggles/dropdowns: azure accent colour
- Update HTML title to "Mod Comms - Intelligent Review"
- Default border radius set to 10px

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:16:26 +00:00
Vadym Samoilenko
44fa8ba527 Remove debug console.log from model_fallback handler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:18:00 +00:00
Vadym Samoilenko
1b60f5deb6 Add console.log to model_fallback handler for debugging
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:12:40 +00:00
Vadym Samoilenko
05e1628086 Add debug logging to model_fallback callback in handlers.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:08:25 +00:00
Vadym Samoilenko
5735b9cbe6 Add fade-in animation for model fallback toast notification
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:04:23 +00:00
Vadym Samoilenko
efa6e772e0 Add toast notification when primary Gemini model falls back to backup
Backend: thread on_fallback callback through analysis chain
(gemini_service → agents → analysis_service → handlers). The handler
sends a 'model_fallback' WebSocket message exactly once per analysis
when the primary model is unavailable.

Frontend: handle 'model_fallback' WS message and show a dismissible
yellow toast at the bottom of the screen with an 8-second auto-dismiss.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:00:12 +00:00
Vadym Samoilenko
9ecabafa2b Fix Gemini http_options timeout unit: seconds → milliseconds
google-genai SDK expects http_options 'timeout' in milliseconds.
Passing 45 (seconds) was interpreted as 45ms → ~1s deadline,
which Google API rejected with 400 INVALID_ARGUMENT
'Manually set deadline 1s is too short. Minimum allowed deadline is 10s.'

Primary: 45_000ms (45s), Fallback: 150_000ms (150s)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:52:25 +00:00
Vadym Samoilenko
74585c5c18 Fix Gemini timeout by using HTTP-level timeout on separate clients
asyncio.wait_for cannot reliably cancel SDK-internal HTTP connections.
Replace with two genai.Client instances — one per model — each configured
with http_options={'timeout': N} so the TCP connection is actually torn
down when the deadline is reached.

Primary model: 45s, Fallback model: 150s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:49:11 +00:00
Vadym Samoilenko
a9bd6a2775 Increase fallback Gemini timeout from 60s to 150s
Log analysis showed fallback model responses up to 154s under parallel
load. 60s was too aggressive and would cause false timeouts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:43:39 +00:00