Skip to content

Technology Stack

Versions captured 2026-06-24 from the repos’ manifest files.

Technology Version Role
Python 3.12 Language / runtime
Flask 3.1.2 Web framework (Blueprints + MethodView)
SQLAlchemy 2.0.46 ORM
psycopg2 2.9.11 PostgreSQL driver / raw pool
Redis (client lib) 7.1.0 Python Redis client (cache + RQ)
RQ 2.6.1 Background job queue
Elasticsearch (client) 9.2.1 Search / time-series
Gunicorn 24.1.1 WSGI server
Marshmallow 3.26.2 Serialization schemas
Sentry SDK 2.51.0 Error / performance monitoring
📎 Evidence
  • Python 3.12 runtimepw-enterprise/.python-version:1 (3.12) and pw-enterprise/pyproject.toml:10 (requires-python = ">=3.12") both pin Python 3.12. ✅
  • Flask 3.1.2pw-enterprise/pyproject.toml:44 (flask>=3.1.2) and pw-enterprise/uv.lock:1452-1453 resolve to 3.1.2. ✅
  • SQLAlchemy 2.0.46pw-enterprise/uv.lock:6393-6394 resolves to 2.0.46; transitive via flask-sqlalchemy (pyproject.toml:47), not declared directly. ✅
  • psycopg2 2.9.11pw-enterprise/pyproject.toml:70 (psycopg2-binary>=2.9.11) and :103 (psycopg2>=2.9.11); uv.lock:4690-4691 resolves to 2.9.11. ✅
  • redis client 7.1.0pw-enterprise/uv.lock:5730-5731 resolves to 7.1.0; cache.py:10 (import redis) confirms direct use. Transitive (via rq), not in pyproject.toml. ✅
  • RQ 2.6.1pw-enterprise/pyproject.toml:82 (rq>=2.6.1) and uv.lock:6097-6098 resolve to 2.6.1. ✅
  • Elasticsearch client 9.2.1pw-enterprise/uv.lock:1132-1133 resolves to 9.2.1; pyproject.toml:37 floor is >=9.2.0 (one patch below). ✅
  • Gunicorn 24.1.1pw-enterprise/uv.lock:2097-2098 resolves to 24.1.1; pyproject.toml:51 floor is >=23.0.0 (a major below the resolved version). ✅
  • Marshmallow 3.26.2pw-enterprise/uv.lock:3447-3448 resolves to 3.26.2; transitive via flask-marshmallow/marshmallow-sqlalchemy, not declared directly. ✅
  • Sentry SDK 2.51.0pw-enterprise/pyproject.toml:85 (sentry-sdk[langchain,langgraph,rq]>=2.47.0) and uv.lock:6278-6279 resolve to 2.51.0. ✅
Technology Version Role
LangChain 1.2.7 LLM abstraction / orchestration
LangGraph 1.0.7 Stateful multi-agent graphs
CrewAI 1.6.1 Role-based agent framework
OpenAI SDK 2.16.0 LLM vendor
Anthropic SDK 0.76.0 LLM vendor
Groq 0.37.1 Fast-inference LLM vendor
google-genai (Gemini) 1.60.0 LLM / document extraction
Cohere 5.20.2 Embeddings / LLM vendor
Langfuse 4.5.1 LLM tracing / observability
📎 Evidence
  • LangChain 1.2.7pw-enterprise/pyproject.toml:12 (langchain>=1.2.6) and uv.lock:2644-2645 resolve to 1.2.7. ✅
  • LangGraph 1.0.7pw-enterprise/pyproject.toml:16 (langgraph>=1.0.6) and uv.lock:2834-2835 resolve to 1.0.7. ✅
  • CrewAI 1.6.1pw-enterprise/pyproject.toml:33 (crewai>=1.6.1) and uv.lock:853-854 resolve to 1.6.1. ✅
  • OpenAI SDK 2.16.0pw-enterprise/pyproject.toml:63 (openai>=2.9.0) and uv.lock:3999-4000 resolve to 2.16.0. ✅
  • Anthropic SDK 0.76.0pw-enterprise/uv.lock:154-155 resolves to 0.76.0; transitive via langchain-anthropic (pyproject.toml:13); .env:136 ANTHROPIC_API_KEY confirms wiring. ✅
  • Groq 0.37.1pw-enterprise/uv.lock:1955-1956 resolves to 0.37.1; v3/video_analysis.py:25 (from groq import Groq) and .env:132 GROQ_API_KEY confirm use. ✅
  • google-genai 1.60.0pw-enterprise/pyproject.toml:97 (google-genai>=1.60.0) and uv.lock:1850-1851 resolve to 1.60.0. ✅
  • Cohere 5.20.2pw-enterprise/pyproject.toml:32 (cohere>=5.20.0) and uv.lock:813-814 resolve to 5.20.2. ✅
  • Langfuse 4.5.1pw-enterprise/pyproject.toml:105 (langfuse>=4.5.1) and uv.lock:2815-2816 resolve to 4.5.1. ✅
Technology Version Role
React / React DOM 19.1.0 UI framework
Vite+ (vite-plus) latest Build toolchain (wraps Vite/Vitest/Oxlint/Oxfmt)
TypeScript 5.9.3 Language
React Router 7.5.1 Routing
TanStack React Query 4.32.0 Server-state / data fetching
Zustand 5.0.8 Client state
nuqs 2.4.3 URL-state
Tailwind CSS 4.2.2 Styling (+ shadcn/Radix)
Highcharts / Recharts 10.1.0 / 2.15.3 Charting
Axios 1.8.4 HTTP client
Sentry React 9.13.0 Error / performance monitoring

vite-plus floats to latest in package.json (the Vite+ toolchain self-manages its tool versions); all other dependencies use caret (^) ranges that allow minor/patch upgrades — the numbers above are the declared floors.

📎 Evidence
  • React / React DOM 19.1.0pw-enterprise-frontend/package.json:108 (react: ^19.1.0) and :114 (react-dom: ^19.1.0). Caret range, not exact pin. ✅
  • vite-plus pinned latestpw-enterprise-frontend/package.json:171 ("vite-plus": "latest"); :168 aliases vite to npm:@voidzero-dev/vite-plus-core@latest. ✅
  • Vite+ unified toolchainpw-enterprise-frontend/CLAUDE.md:1 describes it built on Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt; package.json:177 overrides vitest to @voidzero-dev/vite-plus-test. ✅
  • TypeScript 5.9.3pw-enterprise-frontend/package.json:167 ("typescript": "^5.9.3") in devDependencies. Caret range. ✅
  • React Router 7.5.1pw-enterprise-frontend/package.json:125 ("react-router": "^7.5.1"). ✅
  • TanStack React Query 4.32.0pw-enterprise-frontend/package.json:79 ("@tanstack/react-query": "^4.32.0"). ✅
  • Zustand 5.0.8pw-enterprise-frontend/package.json:146 ("zustand": "^5.0.8"). ✅
  • nuqs 2.4.3pw-enterprise-frontend/package.json:105 ("nuqs": "^2.4.3"). ✅
  • Tailwind CSS 4.2.2pw-enterprise-frontend/package.json:166 ("tailwindcss": "^4.2.2") and :153 (@tailwindcss/vite: ^4.2.2). ✅
  • Highcharts 10.1.0pw-enterprise-frontend/package.json:90 ("highcharts": "^10.1.0"). ✅
  • Recharts 2.15.3pw-enterprise-frontend/package.json:133 ("recharts": "^2.15.3"). ✅
  • Axios 1.8.4pw-enterprise-frontend/package.json:81 ("axios": "^1.8.4"). ✅
  • Sentry React 9.13.0pw-enterprise-frontend/package.json:75 ("@sentry/react": "^9.13.0"). ✅
  • Versions are caret (^) floors, not exact pinspw-enterprise-frontend/package.json uses ^ ranges throughout (e.g. :108 react: ^19.1.0, :125 react-router: ^7.5.1); only vite-plus (:171) floats to latest. Footnote corrected accordingly. ✅
Technology Version Role
PostgreSQL server 12.12 · client 14.23 System of record (local on each VM, ×2 instances; + GCP Cloud SQL via proxy on dev)
Redis server 8.8.0 (dev) / 6.0.16 (prod) · 7.x (client) Cache + RQ queues
MySQL server 8.0.46 Secondary local DB on the VMs
Elasticsearch 9.2.x–9.4.x (client) Search / time-series — remote (not hosted on the VMs)
RabbitMQ 3.9.27 (dev only) Message broker (likely Airflow/Celery; no app call-site verified)
Apache HTTP Server 2.4.52 Web server / ingress on both VMs (no nginx)
BigQuery (GCP, client 3.40.0) Analytics warehouse
Cloudflare (Wrangler) 4.81.1 Pages + Workers + Tunnel hosting / deploy
Node.js 22 (CI lts/*) · 18.17.0 dev VM / 26.2.0 prod VM Build (CI) and on-host runtimes

Server versions confirmed from the VMs on 2026-06-25 (see Environments & Infrastructure → Cloud Inventory). Postgres servers are local 12.12 on each box; Redis server major differs by environment (8.x dev, 6.x prod); Elasticsearch is a remote/managed cluster (not listening on either VM).

📎 Evidence
  • PostgreSQL server 12.12 (confirmed)sudo -u postgres psql -tc 'select version();' on both VMs (2026-06-25) = PostgreSQL 12.12 (Ubuntu 12.12-0ubuntu0.20.04.1); ss -tlnp shows two local postgres instances per box (:5432, :5433). Client is psql 14.23. .env:140-141 POSTGRES_HOST/POSTGRES_PORT confirm wiring. ✅
  • Redis server major differs by env (confirmed)redis-server --version: pw-dev v=8.8.0, pw-prod v=6.0.16; Python redis client pinned 7.1.0 (prod) / 7.4.0 (test) / 5.2.1 (dev) per the deployed uv.locks. .env:41-43 confirm connectivity. ✅
  • Elasticsearch is remote (confirmed) — client pinned 9.2.1 (prod) / 9.4.0 (test) / 8.17.1 (dev) in the deployed uv.locks; :9200 is absent from ss -tlnp on both VMs → managed/remote cluster, not VM-hosted. .env:26 elastic_key confirms connectivity. ✅
  • MySQL 8.0.46, Apache 2.4.52, RabbitMQ 3.9.27 (from VMs)mysql --version = 8.0.46, apache2 -v = Apache/2.4.52, sudo rabbitmqctl version (pw-dev) = 3.9.27. RabbitMQ listens only on pw-dev (beam.smp AMQP :5672); likely the Airflow/Celery broker — no app call-site verified. ⚠️
  • BigQuery client 3.40.0pw-enterprise/pyproject.toml:100 (google-cloud-bigquery>=3.39.0) and uv.lock:1745-1746 resolve to 3.40.0. Doc correctly labels it ‘client’. ✅
  • Wrangler 4.81.1 (Cloudflare Pages)pw-enterprise-frontend/package.json:172 ("wrangler": "^4.81.1"), deploy script :15 (wrangler pages deploy dist), wrangler.toml:1-5 sets pages_build_output_dir = "dist". ✅
  • Node version: CI uses lts/* (Node 22)pw-enterprise-frontend/.github/workflows/playwright.yml:26 uses node-version: lts/*; no .nvmrc/.node-version/engines field is declared, so the project floor is inferred (package-lock.json:2044 shows a transitive "node": ">=18.0.0"). Table now cites the CI version. ✅

External services the platform calls out to, identified from the backend .env and the library/ integration wrappers. (Names only — no credentials.)

Service Used for
OpenAI LLM / embeddings
Anthropic (Claude) LLM
Groq Fast-inference LLM
Google Gemini LLM / document extraction
Cohere Embeddings / LLM
Cerebras Fast-inference LLM
DeepSeek LLM
Perplexity LLM / answer engine
OpenRouter Multi-model gateway
SambaNova (Sambaverse) LLM
LlamaIndex (local library) Indexing / retrieval
📎 Evidence
  • OpenAI LLM providerpw-enterprise/library/llm_completions.py:13 imports from openai import OpenAI and PROVIDER_CONFIGS["openai"] wires api_key_env="openai_api_key"; .env:3,129 define openai_api_key/OPENAI_API_KEY. ✅
  • Anthropic / Claude LLMpw-enterprise/ai_twin/respondents/agents.py:19,46 imports ChatAnthropic and reads claude_key; pw-enterprise/v3/tools.py:8048-8049 instantiates ChatAnthropic(model_name="claude-sonnet-4-5", api_key=claude_key). ✅
  • Groq fast-inference LLMpw-enterprise/library/llm_completions.py:33-35 config api_key_env="groq_api_key", base_url="https://api.groq.com/openai/v1"; pw-enterprise/ai_twin/group/main.py:9,1489 imports and instantiates ChatGroq. ✅
  • Google Gemini LLMpw-enterprise/app.py:5859-5860 builds ChatGoogleGenerativeAI(model="gemini-3-flash-preview"); gemini_grounded_call defined in pw-enterprise/library/ai_services.py:63 and imported in app.py:166. ✅
  • Coherepw-enterprise/api/planner.py:12,63 does import cohere and cohere_api_key = os.environ["cohere_api_key"]; .env:4 defines the key. ✅
  • Cerebras fast-inference LLMpw-enterprise/v3/langraph_main.py:30,397-399 reads CEREBRAS-API-KEY, imports from cerebras.cloud.sdk import Cerebras, and calls cerebras_client.chat.completions.create; dep in pyproject.toml:30. ✅
  • DeepSeek LLMpw-enterprise/api/assets/routers/transparency.py:2280-2284 active ChatOpenAI(openai_api_key=deepseek_api_key, model="deepseek-chat", base_url="https://api.deepseek.com"); secret mapped in app.py:43. ✅
  • Perplexity answer enginepw-enterprise/library/ai_services.py:311-316 reads perplexity_api_key and POSTs to https://api.perplexity.ai/chat/completions with a Bearer header. ✅
  • OpenRouter gatewaypw-enterprise/config/constants.py:48 reads OPENROUTER_API_KEY = os.environ.get("openrouter", ""); api/assets/routers/conversations.py:4126 sets openai_api_base="https://openrouter.ai/api/v1". ✅
  • SambaNova LLMpw-enterprise/api/planner.py:9591-9598 active ChatOpenAI(openai_api_key=SAMBAVERSE_API_KEY, openai_api_base="https://api.sambanova.ai/v1", tags=[..., "sambanova"]); secret mapped in app.py:46. ✅
  • LlamaIndex (local library)pw-enterprise/api/assets/routers/assets_uploads.py:110 imports from llama_index.core import SimpleDirectoryReader; app.py:32 loads LLAMAINDEX-API-KEY but no LlamaIndex Cloud endpoint call was found — so this is the local library, as the table now states. ✅

The providers above are reached through concrete model IDs. The list below covers only IDs referenced in active (non-commented) code on the app (prod) branch, grouped by provider. The active model-ID inventory is nearly identical across the three deploy branches — but the wiring is not: which call site or feature selects which model diverges in ~20 places (7 of them same-call-site model swaps, the rest branch-only features). All per-branch differences are catalogued in Model differences across branches below. Two facts frame the whole table:

  • gemini-3-flash-preview is the Gemini workhorse (~53 active call sites) and gpt-4.1 is the most-referenced model overall (~350 active call sites) — together they carry the bulk of production generation.
  • Selection is mostly hardcoded per call site. There is no single global model registry; each module names its model inline. The only centralized controls are the frontend-facing passthrough allow-list (library/llm_completions.py:32-64) and two module-level constants (MAVEN_MODEL_SPEC, GPT5_MODEL) — see the Evidence block.

Counts are approximate active-reference tallies (~refs), not exact.

Model ID Type ~refs Used for
gpt-4.1 chat ~350 Primary chat model across twin / maven / v3 / api / cron
gpt-4.1-mini chat ~43 Secondary chat; also the openai passthrough default
gpt-4.1-nano chat 4 Small/cheap variant (passthrough allow-list)
gpt-4o chat ~16 Meetings insight generation + fallback
gpt-4o-mini chat 7 Survey / intent-insights chat
gpt-4o-2024-08-06 chat (pinned) 1 Product intelligence (dated snapshot)
gpt-4 chat 2 Maven LangGraph env default
gpt-4.5-preview chat 1 v3 “AI storm” multi-model ensemble
gpt-3.5-turbo chat 4 Reports + conversations
gpt-3.5-turbo-instruct completion ~14 Legacy completions-style planner engine
gpt-3.5-turbo-0125 base ~10 Base for fine-tuned ad-creative models
gpt-3.5-turbo-1106 base / tokenizer ~10 Token-count helper + base for model-router fine-tune
gpt-5 chat 3 Twin respondent prompt composer (CLI)
gpt-5-mini chat 3 Twin respondent agents + maven scope classification
gpt-5.1 chat 1 Maven deep-agent tool call
gpt-5.4 chat 3 Maven orchestrator (MAVEN_MODEL_SPEC) + passthrough allow-list
gpt-5.4-mini chat 3 Passthrough allow-list
gpt-5.5 chat 1 Premium report design (env-overridable)
gpt-realtime-1.5 realtime voice 1 Realtime model reference (also called from the browser)
o1 reasoning 4 Persona generation reasoning
o3 reasoning 6 Persona cues + meetings reasoning
o3-mini reasoning 3 LinkedIn + homepage reasoning
o4-mini reasoning 1 Misc reasoning task
text-embedding-3-large embeddings 7 Vector search / report summarization
text-embedding-3-small embeddings 2 Maven embeddings + persona clustering
text-embedding-ada-002 embeddings 2 Legacy embeddings (homepage, FB audiences)
tts-1 speech (TTS) 3 Persona / creative-evaluation voice
gpt-image-2 image gen 4 Ad creative image generation

Fine-tuned OpenAI models (ProfitWheel org):

Fine-tuned model Base Used for
ft:…:google-ad-genius:9hGemqwG gpt-3.5-turbo-0125 Google ad creative generation
ft:…:instagram-v2:9Zx2tg5u gpt-3.5-turbo-0125 Instagram creative generation
ft:…:model-router:9GgS0ypq gpt-3.5-turbo-1106 “Crew” feature model router
ft:…:funnel:7qbzYPcw gpt-3.5-turbo-0613 Google Ads funnel-stage classification
ft:…:audiencename:AYBws9Ok gpt-4o-mini-2024-07-18 Audience-name quality scoring
Model ID Type ~refs Used for
claude-sonnet-4-5 chat 20 Twin respondents, planner, meetings, transparency, IAM
claude-3-7-sonnet-latest chat 1 Meetings analysis
claude-3-5-haiku-latest chat 1 Planner lightweight task
Model ID Type ~refs Used for
gemini-3-flash-preview chat ~53 Dominant Gemini model — meetings, surveys, product intel, v3, twin
gemini-2.5-pro chat 10 File analysis, product intelligence
gemini-2.5-flash chat 2 Persona generation
gemini-2.5-flash-image image gen 2 Image-capable Gemini variant
gemini-2.0-flash chat 5 Maven tools
gemini-3.1-flash-lite chat 3 Lightweight Gemini variant
google/gemma-4-26b-a4b-it chat 1 Twin conversation LLM (user persona)
Model ID Provider ~refs Used for
llama-3.3-70b-versatile Groq 16 Twin group sims, planner, meetings; Groq passthrough default
llama3.3-70b Cerebras 7 Report-resilience fallback model
llama-4-scout Groq 1 Persona-name generation (primary)
llama-3.3-70b Groq 1 Research agent tools
whisper-large-v3 Groq 2 Audio transcription for video analysis
llama-3.1-8b-instant, llama3-70b-8192, llama3-8b-8192, mixtral-8x7b-32768, openai/gpt-oss-20b Groq Passthrough allow-list only (not directly invoked)
Model ID Provider ~refs Used for
deepseek-chat DeepSeek 1 Transparency-report LLM call
sonar Perplexity 2 Web-search chat (primary)
sonar-pro Perplexity 2 Web-search chat (fallback)
Model ID Type ~refs Used for
@cf/black-forest-labs/flux-1-schnell image gen 1 Persona profile-picture generation (dev env)

The React app calls a few models directly from the browser, in addition to the server-side models above:

Model ID Provider / transport Used for
gpt-realtime-1.5 OpenAI Realtime (WebRTC) AI-twin live audio call
gpt-4o-transcribe OpenAI (realtime transcription) Speech-to-text for the audio call
llama-3.3-70b-versatile Groq (browser SDK) Chat sidebar, activity summaries, survey parsing
gpt-4o (fallback) via backend /chat_gpt_response Streaming twin chat (model passed as query param)
📎 Evidence

Representative call site per model ID (one active, non-commented site each; grep the exact ID for every occurrence):

Model ID Representative call site
gpt-4.1 ai_twin/respondents/universe_stage_fetcher.py:683
gpt-4.1-mini ai_twin/group/main.py:882
gpt-4.1-nano library/llm_completions.py:56
gpt-4o api/product.py:3173
gpt-4o-mini api/survey.py:3790
gpt-4o-2024-08-06 api/product.py:3198
gpt-4 maven/deep_agent_langgraph.py:145
gpt-4.5-preview v3/tools.py:8046
gpt-3.5-turbo api/reports.py:3236
gpt-3.5-turbo-instruct api/planner.py:1039
gpt-3.5-turbo-0125 api/planner_creative.py:9462
gpt-3.5-turbo-1106 library/openai_helpers.py:112
gpt-5 ai_twin/respondents/respondent_prompt_composer.py:55
gpt-5-mini ai_twin/respondents/agents.py:330
gpt-5.1 maven/deep_tools.py:733
gpt-5.4 maven/deep_agent_profiles.py:16
gpt-5.4-mini library/llm_completions.py:60
gpt-5.5 maven/report_designer.py:217
gpt-realtime-1.5 api/misc.py:2645 (backend) · pw-enterprise-frontend/src/components/atoms/AitwinAudioCall.jsx:737 (browser)
gpt-4o-transcribe pw-enterprise-frontend/src/components/atoms/AitwinAudioCall.jsx:742 (browser)
o1 api/assets/routers/personas.py:3204
o3 api/assets/routers/meetings.py:9196
o3-mini api/linkedin.py:1452
o4-mini api/assets/routers/misc.py:236
text-embedding-3-large cron/run_reports.py:169
text-embedding-3-small maven/deep_utils.py:685
text-embedding-ada-002 api/homepage.py:1731
tts-1 app.py:3818
gpt-image-2 api/planner_creative.py:6455
ft:…:google-ad-genius:9hGemqwG api/planner_creative.py:9083
ft:…:instagram-v2:9Zx2tg5u api/planner_creative.py:1655
ft:…:model-router:9GgS0ypq api/misc.py:2227
ft:…:funnel:7qbzYPcw api/google_ads.py:1715
ft:…:audiencename:AYBws9Ok library/audience_buckets.py:158
claude-sonnet-4-5 ai_twin/respondents/agents.py:338
claude-3-7-sonnet-latest api/meetings.py:2956
claude-3-5-haiku-latest api/planner.py:9694
gemini-3-flash-preview library/ai_services.py:267
gemini-2.5-pro api/files.py:121
gemini-2.5-flash api/assets/routers/personas.py:507
gemini-2.5-flash-image api/creative_consumrai.py:636
gemini-2.0-flash maven/tools.py:3349
gemini-3.1-flash-lite maven/generative_ui.py:198
google/gemma-4-26b-a4b-it api/assets/routers/conversations.py:4121
llama-3.3-70b-versatile ai_twin/group/main.py:1491 (backend) · useGroq.js:49, useGroqEventSummary.js:66, useRespondents.js:739 (browser)
llama3.3-70b (Cerebras) library/report_resilience.py:620
llama-4-scout library/report_resilience.py:618
llama-3.3-70b (Groq) research_setup/utils/functions.py:322
whisper-large-v3 v3/video_analysis.py:171
Groq passthrough allow-list (llama-3.1-8b-instant, llama3-70b-8192, llama3-8b-8192, mixtral-8x7b-32768, openai/gpt-oss-20b) library/llm_completions.py:40-44
deepseek-chat api/assets/routers/transparency.py:2283
sonar library/ai_services.py:321
sonar-pro library/ai_services.py:332
@cf/black-forest-labs/flux-1-schnell api/assets/routers/personas.py:5431
gpt-4o (browser fallback) pw-enterprise-frontend/src/hooks/conversation/useConversationStreaming.js:3590

Paths are relative to pw-enterprise/ unless prefixed with pw-enterprise-frontend/.

  • gpt-4.1 primary workhorse — active ChatOpenAI(model="gpt-4.1", …) at pw-enterprise/ai_twin/respondents/universe_stage_fetcher.py:683; ~350 active (non-commented) references across the backend. ✅
  • gemini-3-flash-preview Gemini workhorsepw-enterprise/library/ai_services.py:267 (model_name="gemini-3-flash-preview"); ~53 active references. ✅
  • claude-sonnet-4-5pw-enterprise/ai_twin/respondents/agents.py:338 (model_name="claude-sonnet-4-5"); 20 active references. ✅
  • Passthrough allow-list (no direct browser provider calls)pw-enterprise/library/llm_completions.py:32-64 defines PROVIDER_CONFIGS: groq → default llama-3.3-70b-versatile (allow-list lines 39-44); openai → default gpt-4.1-mini (allow-list lines 54-60). Module docstring (llm_completions.py:1-6) states the frontend must not call providers directly. ✅
  • Central model constants (only two)MAVEN_MODEL_SPEC = "openai:gpt-5.4" at pw-enterprise/maven/deep_agent_profiles.py:16; GPT5_MODEL = "gpt-5" at pw-enterprise/ai_twin/respondents/respondent_prompt_composer.py:55 (same-line comment notes it as a placeholder alias). No model defaults exist under config/. ✅
  • Fine-tuned modelsgoogle-ad-genius active at pw-enterprise/api/planner_creative.py:9083; instagram-v2 at :1655; model-router at api/misc.py:2227; funnel at api/google_ads.py:1715; audiencename at library/audience_buckets.py:158. ✅
  • Server-side Fluxpw-enterprise/api/assets/routers/personas.py:5431 (model_name = "@cf/black-forest-labs/flux-1-schnell"). ✅
  • Workers AI catalog is generated, not usedpw-enterprise-frontend/worker-configuration.d.ts:2 header: // Generated by Wrangler by running \wrangler types`; the AiModels interface (:3767+) is a TypeScript catalog of every Workers-AI-supported model. Grepping AI.run(/env.AI.run(/.run(“@cf/acrosssrc/andfunctions/returns zero hits — theAIbinding (declaredfunctions/_middleware.ts:10, wrangler.toml:11-12`) is never invoked. ✅
  • Browser-side model calls — OpenAI Realtime gpt-realtime-1.5 / gpt-4o-transcribe at pw-enterprise-frontend/src/components/atoms/AitwinAudioCall.jsx:737,742; Groq llama-3.3-70b-versatile at useGroq.js:49, useGroqEventSummary.js:66, useRespondents.js:739; backend passthrough fallback gpt-4o at useConversationStreaming.js:3590. ✅
  • Commented-out (excluded) refs — e.g. claude-haiku-4-5 (maven/deep_agent.py:601), dall-e-3 (api/planner_creative.py:6444,6492, superseded by gpt-image-2), gemini-3.1-pro-preview, and ~14 commented gpt-4.1 lines are not counted as active. ✅

Model differences across branches (dev · test · prod)

Section titled “Model differences across branches (dev · test · prod)”

The tables above reflect the app (prod) branch. The three deploy branches share a near-identical model inventory — comparing every active model-ID literal, only 3 IDs are active on some branches but not all (plus one commented-only). But inventory parity is not wiring parity: ~20 shared call sites, features, or whole files invoke a different model — or a model prod doesn’t call at all — depending on branch. The consistent pattern: dev/test run ahead of prod app (newer features, plus a partial migration of some Gemini calls to newer/cheaper models), while app is the conservative baseline; dev occasionally diverges from test too.

Re-verified 2026-07-15 against freshly-fetched refs — origin/dev @ 6f58193, origin/test @ d463768, origin/app @ 59d0803. These are unchanged from the 2026-06-24 capture: no new commits have landed on any deploy branch, so this is already the latest code. Curated invoked-model counts are dev 56, test 55, prod 55 (a broad literal grep returns ~77/75/75, but ~20 per branch are token-cost dict keys, truncated gemini-2.x version-prefix partials, env-var names like DEEPSEEK-API-KEY, and helper identifiers — not model invocations).

There are three kinds of difference:

1 · Inventory differences — a model ID active on some branches, not all

Section titled “1 · Inventory differences — a model ID active on some branches, not all”
Model ID prod (app) test dev Why
gpt-4o-transcribe prod-only; dev/test transcribe with whisper-large-v3 at the same transcribe_audio() — a swap (Table 2)
gemini-2.5-flash-lite dev/test swapped 4 shared gemini-2.0-flash call sites to it (Table 2)
claude-3-5-sonnet-20241022 only in dev-only files (Table 3)
claude-3-5-sonnet-latest commented two #-commented refs in dev’s v3/maven.py — excluded

2 · Model swaps — the same shared call site invokes a different model per branch

Section titled “2 · Model swaps — the same shared call site invokes a different model per branch”

This is the class the old inventory-only view missed. The IDs all exist on every branch, so a set diff can’t see them — but the model chosen at a given call site diverges:

Feature — call site prod (app) test dev
Video transcription — transcribe_audio · v3/video_analysis.py gpt-4o-transcribe whisper-large-v3 whisper-large-v3
Focus-group AEO responses — get_llm_responses_for_questions · api/assets/routers/meetings.py gemini-2.0-flash gemini-2.5-flash-lite gemini-2.5-flash-lite
Focus-group executor — ai_twin_focused_group_execute_plan_func · api/meetings.py gemini-2.0-flash gemini-2.5-flash-lite gemini-2.5-flash-lite
Keyword-plan SEM filter — create_keyword_plan · api/intent_planner.py gemini-2.0-flash gemini-2.5-flash-lite gemini-2.5-flash-lite
Plan-input generator — generate_plan_inputs · v3/tools.py gemini-2.0-flash gemini-2.5-flash-lite gemini-2.5-flash-lite
Grounded web search — gemini_grounded_call · library/ai_services.py gemini-3-flash-preview (Gemini REST) gpt-4o-mini (OpenAI) gpt-4o-mini (OpenAI)
Custom grounded search — gemini_custom_grounded_func · api/misc.py gemini-3-flash-preview gemini-3-flash-preview gemini-2.5-flash

Two themes dominate: dev/test migrating gemini-2.0-flashgemini-2.5-flash-lite across the focus-group / keyword / planning features, and the grounded-search helper re-platformed from Gemini to OpenAI gpt-4o-mini on dev/test. The last row shows dev alone diverging from both prod and test.

3 · Branch-only features — a call site or whole file present on only some branches

Section titled “3 · Branch-only features — a call site or whole file present on only some branches”
Feature On Model(s) Nature
Creative-intelligence params & scoring — ci_select_parameters, performance_elements… · api/assets/routers/meetings.py dev + test gpt-4.1-mini, gpt-4.1 new call sites (absent on app)
Content-creator tools — code/blog/email/messaging/ads_creator · v3/tools.py dev only gpt-4.1 new call sites
Survey Action Plan — GenerateSurveyActionPlan.post · api/reports.py dev + test gpt-4o new call site
Maven schedule-prompt validate/enhance · api/scheduled_report.py dev + test gpt-5-mini, gpt-4.1-mini new call sites
Premium report cover image — _generate_maven_premium_report_cover_url · research_setup/api/routes.py test only gpt-image-2 new call site
Segmentation→JSON — run_survey_and_segmentation · research_setup/utils/functions.py app only llama-3.3-70b-versatile call site removed on dev/test
Predictive-twin package · predictive_twin/*.py dev + test gpt-4.1, o3 whole package absent on app
Maven v3 graph · v3/maven.py dev only gpt-4.1, gemini-2.0-flash, llama3.3-70b, claude-3-5-sonnet-20241022 whole file absent on app/test
Question classification · fastapi_app/services/question_classification.py dev only claude-3-5-sonnet-20241022 whole file absent on app/test
Respondent memory summarizer · ai_twin/respondents/memory_summarizer.py dev only gemini-2.5-flash whole file absent on app/test
📎 Evidence

Verified 2026-07-15 by reading each call site on origin/app, origin/dev, origin/test (47-agent cross-check; every finding independently re-derived, raw-diff noise refuted). Paths relative to pw-enterprise/.

Inventory (set-membership) diffsapp\(dev∪test) = gpt-4o-transcribe, dev\(app∪test) = claude-3-5-sonnet-20241022, (dev∩test)\app = gemini-2.5-flash-lite. Prod is not a strict subset. Arithmetic: shared core 54 + prod’s gpt-4o-transcribe = 55; + dev’s two extras = 56; + test’s one extra = 55. ✅

Swaps (same call site, different model per branch):

  • transcribe_audioapp:v3/video_analysis.py:789gpt-4o-transcribe; dev/test same function → whisper-large-v3. ✅
  • get_llm_responses_for_questions (AEO gemini slot) — app:api/assets/routers/meetings.py:3115 gemini-2.0-flashdev:4522 / test:4589 gemini-2.5-flash-lite. ✅
  • ai_twin_focused_group_execute_plan_funcapp:api/meetings.py:1509 gemini-2.0-flashdev:1515 / test:1517 gemini-2.5-flash-lite. ✅
  • create_keyword_planapp:api/intent_planner.py:957 gemini-2.0-flashdev:958 / test:957 gemini-2.5-flash-lite. ✅
  • generate_plan_inputsv3/tools.py:5024 gemini-2.0-flash (app) → gemini-2.5-flash-lite (dev/test). ✅
  • gemini_grounded_callapp:library/ai_services.py:69 gemini-3-flash-preview (Gemini REST) → dev:117 / test:120 gpt-4o-mini via a GROUNDED_MODEL constant on the OpenAI Responses API (function re-platformed, signature preserved). ✅
  • gemini_custom_grounded_funcapp/test:api/misc.py gemini-3-flash-previewdev:2794 gemini-2.5-flash (dev-only divergence). ✅

Branch-only call sites & files:

  • api/assets/routers/meetings.pyci_select_parameters gpt-4.1-mini (dev:846/test:848) + CI scoring gpt-4.1 (dev:8292/test:8370); none on app. ✅
  • v3/tools.py — content-creator tools gpt-4.1 at dev:12544/13118/13189/13260/13339; absent on app and test. ✅
  • api/reports.py:5002GenerateSurveyActionPlan.post gpt-4o on dev/test; absent on app. ✅
  • api/scheduled_report.py:122,187gpt-5-mini / gpt-4.1-mini on dev/test; absent on app. ✅
  • research_setup/api/routes.py:149gpt-image-2 on test only. ✅
  • research_setup/utils/functions.py:3051llama-3.3-70b-versatile on app only (site removed on dev/test). ✅
  • predictive_twin/{intent_forecast,mentions_forecast,predictive_prompt_composer}.pygpt-4.1 + o3; git cat-file -e fails on origin/app. ✅
  • v3/maven.py (dev-only) + fastapi_app/services/question_classification.py:24 (dev-only) → claude-3-5-sonnet-20241022; ai_twin/respondents/memory_summarizer.py (dev-only) → gemini-2.5-flash. ✅
  • Refuted as noisedaily_failed_reports_alert.py (no model call at all), v3/langraph_main.py (all models identical; raw-diff hits were line-offset artifacts), and main.py/library/utils.py (DEEPSEEK-API-KEY/LLAMAINDEX-API-KEY are Key-Vault secret names, not model IDs) were flagged by the literal diff but carry no real per-branch model difference. ✅
Service Used for
fal.ai Image / media generation
Replicate Model hosting / generation
Stability AI Image generation
Leonardo AI Image generation
Midjourney (GoAPI / TheNextLeg) Image generation
Napkin Visual / diagram generation
Tavus AI video / avatars
Whisper API Audio transcription
📎 Evidence
  • fal.ai media generationpw-enterprise/api/meetings.py:3105,3251 imports fal_client and calls fal_client.submit("fal-ai/flux-pro/v1.1", ...); dep in pyproject.toml:39; key loaded in app.py:35. ✅
  • Replicate generationpw-enterprise/api/planner_creative.py:29,93,7149-7150 does import replicate, reads REPLICATE_API_TOKEN, and calls replicate.run(...); dep in pyproject.toml:80. ✅
  • Stability AI image genpw-enterprise/api/assets/routers/personas.py:4232,4234 POSTs to https://api.stability.ai/v2beta/stable-image/generate/core with Bearer {stability_ai_token}. ✅
  • Leonardo AI image genpw-enterprise/api/planner_creative.py:92,7551,7565 reads leonardo_key and calls https://cloud.leonardo.ai/api/rest/v1/generations with Bearer {leonardo_key}. ✅
  • Midjourney via GoAPI + TheNextLegpw-enterprise/api/planner_creative.py:90,94 read the_next_leg and go_api_midjourney; GoAPI endpoint https://api.midjourneyapi.xyz/mj/v2/imagine at 6641 and TheNextLeg Bearer headers at 6566/6607. ✅
  • Napkin (key only, no call site)napkin_api_key is read at module load in pw-enterprise/config/constants.py:52 and api/assets/main.py:58, but a repo-wide grep found NO HTTP call to any Napkin endpoint. ⚠️ Integration is provisioned but no active call site was found; confirm before listing as an active service.
  • Tavus AI video/avatarspw-enterprise/api/assets/routers/conversations.py:2941,2958,3042,3058 calls https://tavusapi.com/v2/personas and /v2/conversations with x-api-key: TAVUS_API_KEY. ✅
  • Whisper transcriptionpw-enterprise/api/planner_creative.py:95,3258 reads whisperapi_key and posts to https://transcribe.whisperapi.com with a Bearer header. ✅
Service Used for
Langfuse LLM tracing (separate App / Dev / Test projects)
LangSmith LangChain tracing
📎 Evidence
  • Langfuse tracing, separate App/Dev/Test.env:152-166 has four key-pairs (local, DEV, TEST, APP); library/langsmith_metadata.py:16-34 calls get_client() + LangChainInstrumentor().instrument(); scripts/push_see_trace_prompt.py:100-105 selects LANGFUSE_*_KEY_{DEV,TEST,APP}. ✅
  • LangSmith tracingpw-enterprise/library/langsmith_metadata.py:37-57 setup_langsmith_tracing() requires LANGCHAIN_API_KEY then sets LANGCHAIN_TRACING_V2/LANGSMITH_TRACING; dep langsmith in pyproject.toml:17. ✅
Service Used for
Tavily, Serper, SerpWow, ValueSERP Search APIs
DataForSEO SEO / SERP data
ZenRows, WebScrapingAPI, ScrapingNarf, Unwrangle Web scraping
RapidAPI API marketplace (various)
Klazify Domain / company classification
BuzzSumo Content / social analytics
SMMRY Text summarization
NewsData News feeds
US Census API Demographics
Precisely Geo / data enrichment
OpenWeatherMap Weather data
Google Maps Geocoding / maps
📎 Evidence
  • Tavily (env key only — no code usage).env:137 defines TAVILY_API_KEY but a repo-wide grep for tavily across all .py (incl. v3/, ai_twin/, research_setup/) returned ZERO matches: no import, no HTTP call, no LangChain tool. 🔍 Needs a confirmed call site (or a runtime trace) before listing Tavily as an active Search API; currently only a provisioned key.
  • Serper search APIpw-enterprise/api/intent_insights.py:7766,7768 POSTs to https://google.serper.dev/search with X-API-KEY: serper_api_key. ✅
  • SerpWow search APIpw-enterprise/library/google_ads_package.py:4949 calls https://api.serpwow.com/live/search?api_key={}... with serpwow_api_key. ✅
  • ValueSERP search APIpw-enterprise/library/ai_services.py:226,237 reads valueserp_api_key and calls https://api.valueserp.com/search. ✅
  • DataForSEO SERP data (actively called)pw-enterprise/api/intent_insights.py:9635 calls https://api.dataforseo.com/v3/keywords_data/bing/search_volume/live (plus 9362, 9775, 10153, 12256, and v3/tools.py:11984); secret loaded in app.py:36. ✅
  • ZenRows scrapingpw-enterprise/api/misc.py:2044,2065 sends apikey: zenrow_token to https://api.zenrows.com/v1/. ✅
  • WebScrapingAPI scrapingpw-enterprise/api/intent_insights.py:2265 builds https://api.webscrapingapi.com/v1?...&api_key={webscrapingapi}&render_js=1. ✅
  • ScrapingNarf (key read; call site not pinned)pw-enterprise/app.py:309 reads scraping_narf_ai_key = os.environ["scraping_narf_ai_key"] and .env:27 defines it; finder asserts use in 10+ modules but cited only the env read, not an HTTP endpoint. ⚠️ Confirm an actual scrapingnarf API call site.
  • Unwrangle extractionpw-enterprise/api/product.py:96,1590,1598 reads unwrangle_api_key and GETs https://data.unwrangle.com/api/getter/. ✅
  • RapidAPI marketplacepw-enterprise/library/google_ads_package.py:4814,4819 calls https://youtube-v31.p.rapidapi.com/search with x-rapidapi-key header. ✅
  • Klazify classificationpw-enterprise/api/intent_insights.py:155,2017,2061 reads klazify_key and calls klazify_fresh_urls() / klazify_url_fallback(). ✅
  • BuzzSumo analyticspw-enterprise/api/intent_insights.py:623,630 sends api_key: buzz_sumo to https://api.buzzsumo.com/search/articles.json. ✅
  • SMMRY summarizationpw-enterprise/library/algorithms.py:24,258,266 defines smmry() posting to https://api.smmry.com with SM_API_KEY: smmry_key. ✅
  • NewsData feedspw-enterprise/cron/top_daily_news_by_country_cron.py:16,86 reads newsdata_api_key and GETs https://newsdata.io/api/1/latest. ✅
  • US Census demographicspw-enterprise/ai_twin/respondents/universe_stage_fetcher.py:63,247,310 reads CENSUS_API_KEY and calls https://api.census.gov/data/{acs_year}/acs/acs1. ✅
  • Precisely geo enrichmentpw-enterprise/api/household.py:200,207 precisely_household() calls https://api.precisely.com/demographics-segmentation/v1/...; secrets loaded in app.py:33-34. ✅
  • OpenWeatherMap weatherpw-enterprise/api/misc.py:90,2607 reads openweathermap_api_key and calls https://api.openweathermap.org/data/3.0/onecall. ✅
  • Google Maps geocodingpw-enterprise/api/misc.py:2382 calls https://maps.googleapis.com/maps/api/geocode/json?latlng=...&key={pb_google_api_key}. ✅

Retail / commerce data (Traject Data family)

Section titled “Retail / commerce data (Traject Data family)”
Service Marketplace
Rainforest Amazon
BigBox Home Depot
BlueCart Walmart
RedCircle Target
📎 Evidence
  • Rainforest Amazon datapw-enterprise/api/product.py:311,482 have active requests.get("https://api.rainforestapi.com/request", ...) (finder’s cited line 118 is commented, but 311/482 are live). ✅
  • BigBox Home Depot datapw-enterprise/api/social_insights.py:79,670,676 reads bigbox_key and GETs https://api.bigboxapi.com/request; secret mapped in app.py:37. ✅
  • BlueCart Walmart datapw-enterprise/api/social_insights.py:80,530,536 reads bluecart_key and GETs https://api.bluecartapi.com/request; secret mapped in app.py:38. ✅
  • RedCircle Target datapw-enterprise/api/social_insights.py:81,603 reads redcircle_key and GETs https://api.redcircleapi.com/request; secret mapped in app.py:39. ✅
Platform Integration
Meta / Facebook Ads, Business Manager, Power Editor
Google Ads / DV360 Ads
Snapchat Ads (dev + prod apps)
TikTok Ads
Pinterest Ads
Twitter / X Ads / data
LinkedIn Ads (in-house wrapper)
YouTube Data / ads
Spotify Data (in-house wrapper)
Google Analytics / GA4 Analytics
📎 Evidence
  • Meta / Facebook Ads + BM + Power Editorpw-enterprise/library/facebook_package.py:51,75 reads fb_version and calls https://graph.facebook.com/{fb_version}/me?fields=adaccounts; .env:39-40,10-15,20 define facebook + BM + power-editor creds. ✅
  • Google Ads / DV360pw-enterprise/library/google_ads_package.py:51,66 reads google_client_secret + google_ads_auth(); library/dv360_package.py:32-33,36 reads dv360_client_id/secret + dv360_auth(); dep google-ads in pyproject.toml:49. ✅
  • Snapchat Ads (dev + prod apps)pw-enterprise/library/snapchat_package.py:13-16,33-36 reads dev_/prod_snapchat_client_id/secret and branches on environment; .env:29-34 define all three pairs. ✅
  • TikTok Adspw-enterprise/library/tiktok_package.py:20-21,155 reads tiktok_client_id/secret and calls https://business-api.tiktok.com/open_api/v1.3/ad/audience_size/estimate/. ✅
  • Pinterest Adspw-enterprise/library/pinterest_package.py:18-19,43 reads PINTEREST_CLIENT_ID/SECRET and calls https://api.pinterest.com/v5/oauth/token. ✅
  • Twitter / X Adspw-enterprise/api/twitter.py:12,14-15 reads twitter_consumer_key, twitter_access_token(_secret); dep twitter-ads in pyproject.toml:91; five creds in .env:60-64. ✅
  • LinkedIn Ads (in-house wrapper)pw-enterprise/library/linkedin_package.py:19-20,41,157 does OAuth at https://www.linkedin.com/oauth/v2/accessToken and ad targeting at https://api.linkedin.com/rest/adTargetingEntities. ✅ Note: lines 19-20 contain hardcoded default client_id/secret fallbacks (a security smell worth flagging separately).
  • YouTube datapw-enterprise/library/youtube_package.py:14,57 reads youtube_client_secret and builds build("youtube", "v3", credentials=credentials). ✅
  • Spotify (in-house wrapper)pw-enterprise/library/spotify_package.py:6-7 spotify_access_token() calls https://accounts.spotify.com/api/token; no dedicated .env key (creds likely in GCP Secret Manager, per finder note). ✅
  • GA4 analyticspw-enterprise/library/google_analytics_4_package.py:33,44 has google_analytics_auth() + get_kv_user_platform_token(..., "google_analytics"); a separate library/google_analytics_package.py (GA3) also exists. ✅
Service Used for
Google Cloud Platform Compute Engine (the VMs), Cloud SQL (managed Postgres), Cloud Ops/OpenTelemetry agents, BigQuery, Secret Manager, Translate
Cloudflare R2, Images, Browser Rendering, Workers/Pages, Tunnel (VM ingress)
Microsoft Azure Key Vault, Blob Storage (legacy) — migrated off, but Azure Monitor agents still run on the VMs
Sentry Error / performance monitoring
Datadog Metrics / monitoring (agent present on the dev VM)
Mailgun Transactional email
📎 Evidence
  • GCP BigQuery / Secret Manager / Translatelibrary/gcp_secrets.py:13,28 instantiates SecretManagerServiceClient; api/common.py:4 imports bigquery; api/planner_creative.py:107 imports translate_v2; deps in pyproject.toml:100-104. ✅
  • Cloudflare R2 + Images + Browser Renderinglibrary/storage.py:37,104 uses r2.cloudflarestorage.com and api.cloudflare.com/.../images/v1; api/misc.py:2131 calls .../browser-rendering/screenshot; .env:118,120,124-125,144-148 define R2/Images/Browser/general keys. ✅ (Workers/Pages hosting is via frontend Wrangler — not evidenced in backend, but consistent with tech-stack table.)
  • Azure Key Vault + Blob (legacy)library/storage.py:6-7 states the backend “migrated from Azure Blob Storage to Cloudflare R2”; library/secrets.py:109-116 Key-Vault-named functions now delegate to GCP Secret Manager; deps remain in pyproject.toml:27-28 but NO from azure import exists in any .py. ✅ (legacy is accurate)
  • Sentry monitoringpw-enterprise/library/sentry_client.py:41,62 is a dedicated client using SENTRY_API_BASE_URL + SENTRY_API_TOKEN; dep sentry-sdk[langchain,langgraph,rq] in pyproject.toml:85. ✅
  • Datadog monitoringpw-enterprise/cron/iam_checks.py:17-18,106,109 reads both Datadog keys and calls https://api.us3.datadoghq.com/api/v1/synthetics/... with DD-API-KEY/DD-APPLICATION-KEY. ✅
  • Mailgun emailpw-enterprise/airflow_monitor.py:20-22,180-181 reads Mailgun creds and sends via smtplib.SMTP("smtp.mailgun.org", 587) with .login(...). ✅

The full set of declared dependencies from each repo’s manifest, grouped by purpose. Collapsed by default.

Backend — pw-enterprise (Python, ~100 deps)
  • Web / API: flask, flask-cors, flask-sqlalchemy, flask-marshmallow, flask-sse, fastapi[standard], uvicorn, gunicorn, flasgger, security
  • AI frameworks: langchain (+ -anthropic, -community, -groq, -openai, -google-community, -google-genai, -text-splitters, -core, -classic), langgraph (+ -prebuilt, -cli[inmem]), langsmith, crewai, llama-index, langfuse, openinference-instrumentation-langchain
  • LLM / model SDKs: openai, cohere, cerebras-cloud-sdk, google-genai, replicate, fal-client, faiss-cpu
  • Cloud SDKs: google-cloud-bigquery, google-cloud-secret-manager, google-cloud-translate, google-cloud, google-api-python-client, google-ads, boto3, cloudflare, azure-identity, azure-keyvault-secrets, oauth2client, apiclient
  • Ad / social clients: google-ads, twitter-ads (plus in-house library/ wrappers: facebook, linkedin, snapchat, tiktok, pinterest, youtube, spotify, dv360, google-analytics / GA4)
  • Jobs / async: rq, nest-asyncio (plus an in-house Airflow REST client library/airflow_client.py — Airflow itself runs externally and is not a PyPI dependency)
  • Data / search: psycopg2 / psycopg2-binary, sqlalchemy-utils, marshmallow-sqlalchemy, elasticsearch, pandas, db-dtypes
  • Media / docs / OCR: pillow, opencv-python-headless, moviepy, librosa, pozalabs-pydub, pytesseract, cairosvg, svglib, cssutils, imagehash, imutils, favicon; python-docx, python-pptx, pypdf, pdfkit, reportlab, unstructured, tabulate, xmltodict
  • Auth / security: pyjwt, python-jose[cryptography], pyotp, webauthn, security, bandit (dev)
  • ML / numeric: scikit-learn, llvmlite (dev/experimental branches add tensorflow, tensorflow-hub, prophet, matplotlib, crawl4ai)
  • Utilities: python-dotenv, decouple, inflect, feedparser, pytrends, tld, tldextract, user-agents, psutil, icecream, libcst, imagehash, xmltodict
  • Monitoring: sentry-sdk[langchain,langgraph,rq]
  • Tooling: uv, ruff, langsmith-fetch (dev)
Frontend — pw-enterprise-frontend (React, ~150 packages)
  • Core: react 19, react-dom, react-router 7
  • Build / deploy: vite-plus (@voidzero-dev/vite-plus-core), @vitejs/plugin-react, @rolldown/plugin-babel, vite-plugin-svgr, vite-plugin-devtools-json, wrangler, @cloudflare/workers-types, typescript, sass
  • State / data / forms: @tanstack/react-query, zustand, nuqs, react-hook-form, @hookform/resolvers, zod
  • UI: @mui/material (+ icons-material), @radix-ui/* (26 primitives), tailwindcss 4 (+ animate, typography), lucide-react, react-icons, @emotion/react + styled, next-themes, sonner, cmdk, vaul, class-variance-authority, clsx, tailwind-merge
  • Tables / grids: @ag-grid-community/, @ag-grid-enterprise/, @tanstack/react-table, react-window
  • Charts / viz: highcharts (+ react-official, map-collection), @amcharts/amcharts5 (+ geodata), @nivo/*, recharts, @hophiphip/react-fishbone, google-map-react
  • AI (client): @langchain/core, @langchain/langgraph (+ -api, -cli, -sdk), groq-sdk
  • Media: wavesurfer.js, howler, react-media-recorder, react-medium-image-zoom, yet-another-react-lightbox, embla-carousel-react, react-slick, slick-carousel
  • Export / docs: @react-pdf/renderer, jspdf, pdfmake, xlsx (SheetJS), file-saver, downloadjs, html2canvas, html2canvas-pro
  • Auth: @simplewebauthn/browser, otpauth, jose, jwt-decode, react-cookie
  • Dates: date-fns, moment, react-date-range, react-datepicker, react-day-picker
  • HTTP / markdown / misc: axios, query-string, react-markdown (+ rehype-raw, remark-gfm), dompurify, motion, nanoid, uuid, react-beautiful-dnd, react-resizable-panels, input-otp, react-qr-code, react-number-format
  • Monitoring / test: @sentry/react, @sentry/vite-plugin, @playwright/test, allure-playwright
📎 Evidence
  • Web/API grouppw-enterprise/pyproject.toml:40,43-48,51,84,94 — flask, flask-cors, flask-sqlalchemy, flask-marshmallow, flask-sse, fastapi[standard], uvicorn, gunicorn, flasgger, security all present. ✅
  • AI frameworks grouppw-enterprise/pyproject.toml:12-25,33,57,105-106 — langchain(+sub-packages), langgraph(+prebuilt,cli), langsmith, crewai, llama-index, langfuse, openinference-instrumentation-langchain all present. ✅
  • Airflow is an in-house REST client, not a PyPI deppw-enterprise/pyproject.toml has no apache-airflow; library/airflow_client.py (HTTP wrapper) is imported at api/product_health.py:46. Inventory now states this. ✅
  • ~100 backend depspw-enterprise/pyproject.toml app branch: 95 in [project].dependencies + 3 in [dependency-groups].dev = 98 (~100). ✅
  • ~150 frontend pkgspw-enterprise-frontend/package.json: 126 dependencies + 25 devDependencies = 151 (~150). ✅
  • FE Corepw-enterprise-frontend/package.json:108,114,125 (react ^19.1.0, react-dom ^19.1.0, react-router ^7.5.1) — all present. ✅
  • FE Build/deploypw-enterprise-frontend/package.json:149,159,74,164,167,169-172 — all 9 named packages present in devDependencies. ✅
  • Radix = 26 primitivespw-enterprise-frontend/package.json:47-72 contains exactly 26 @radix-ui/* packages; inventory now says 26. ✅
  • FE AI clientpw-enterprise-frontend/package.json:38-42,89 (@langchain/core, @langchain/langgraph + -api/-cli/-sdk, groq-sdk) — all present. ✅

Declared differences across branches (verified 2026-06-24)

Section titled “Declared differences across branches (verified 2026-06-24)”

Comparing the committed manifests across branches, dev and test carry a newer backend dependency set than prod app — most notably a bumped LangChain / LangGraph / LangSmith / OpenAI cluster plus a few extra packages. app is the lowest-version baseline.

Backend — shared dependencies bumped on dev (and test) vs prod app:

Package dev / test prod (app)
langchain >=1.3.1 >=1.2.6
langgraph >=1.2.0 >=1.0.6
langchain-core >=1.4.0 >=1.2.7
langsmith >=0.8.5 >=0.6.4
langchain-anthropic >=1.4.3 >=1.3.1
langchain-openai >=1.2.1 >=1.1.7
langchain-google-community >=4.0.0 >=3.0.5
openai >=2.26.0 >=2.9.0

The full langchain-* / langgraph-* family moves together; the table lists the headline bumps.

Backend — extra packages on dev / test beyond prod app:

Environment Adds (beyond app)
Dev (dev) deepagents==0.6.2 + the bumped LangChain/LangGraph cluster above
Test (test) deepagents==0.6.2, crawl4ai==0.8.0, cryptography>=46.0.6 + the same bumped cluster
Prod (app) — (baseline)

tensorflow, tensorflow-hub, prophet, and matplotlib live in the opt-in [dependency-groups].airflow group (not the core [project].dependencies), so they are not installed by default in any environment. db-dtypes is in the app baseline, not a dev-only extra.

Frontend — only the Vite+ toolchain differs (dev and test share one package.json):

Package dev / test prod (main)
vite-plus (@voidzero-dev/vite-plus-core) ^0.1.18 latest
@vitejs/plugin-react ^5.2.0 ^6.0.1

All other frontend dependencies are identical across Dev / Test / Prod.

Net: the frontend differs only in the Vite+ toolchain, but the backend dev/test branches run a materially newer LangChain / LangGraph / OpenAI stack than prod app — a real source-level version difference, not parity.

📎 Evidence
  • FE vite-plus dev/test ^0.1.18git show origin/dev:package.json & origin/test:package.json (line 171) both "vite-plus": "^0.1.18", vite alias @^0.1.18. ✅
  • FE vite-plus main latestpw-enterprise-frontend/package.json:171 on origin/main "vite-plus": "latest" (vite alias @latest). ✅
  • @vitejs/plugin-react 5.2.0 vs 6.0.1git diff origin/main origin/dev -- package.json shows ^6.0.1^5.2.0; test identical to dev. ✅
  • FE otherwise identicalgit diff origin/main origin/dev -- package.json shows only @vitejs/plugin-react, vite-plus, vite alias version changes + xlsx/overrides reorder. ✅
  • Shared-dependency bumps on dev/testgit diff origin/app origin/dev -- pyproject.toml shows langchain 1.2.61.3.1, langgraph 1.0.61.2.0, langchain-core 1.2.71.4.0, langsmith 0.6.40.8.5, langchain-anthropic 1.3.11.4.3, langchain-openai 1.1.71.2.1, langchain-google-community 3.0.54.0.0, openai 2.9.02.26.0; origin/test bumps the same cluster. Section now documents these. ✅
  • Dev/test extra packagesgit diff origin/app origin/dev and …origin/test -- pyproject.toml: both add deepagents==0.6.2; test also adds crawl4ai==0.8.0 + cryptography>=46.0.6. The earlier bigquery>=0.0.1 entry did not exist (only google-cloud-bigquery>=3.39.0, present in app too) and has been removed. ✅
  • tensorflow/matplotlib are opt-in, db-dtypes is baseline — they live in [dependency-groups].airflow, and db-dtypes is in the app [project].dependencies (:35), not a dev-only extra; the note now states this. ✅
  • App baselinegit show origin/app:pyproject.toml lacks crawl4ai, deepagents, cryptography>=46 and runs the lower LangChain/LangGraph floors; it is the lowest-version baseline. ✅

Deployed runtime versions (captured from VMs 2026-06-25)

Section titled “Deployed runtime versions (captured from VMs 2026-06-25)”

Resolved from each environment’s deployed uv.lock on the VMs (read-only). These are the exact installed versions, not the pyproject.toml floors above. Host topology: live dev checkout = /home/coder/served/pw-enterprise on pw-dev; test + prod co-located on pw-prod (/opt/test, /opt/production).

Library Dev (pw-dev /home/coder/served/pw-enterprise) Test (pw-prod /opt/test) Prod (pw-prod /opt/production)
python (system) 3.12.7 3.12.7 3.12.7
node 18.17.0 26.2.0 26.2.0
flask 3.1.0 3.1.3 3.1.2
sqlalchemy 2.0.38 2.0.49 2.0.46
redis (client) 5.2.1 7.4.0 7.1.0
rq 2.1.0 2.8.0 2.6.1
elasticsearch 8.17.1 9.4.0 9.2.1
gunicorn 21.2.0 (sys) 26.0.0 24.1.1
uvicorn 0.34.0 0.46.0 0.40.0
langchain 0.3.18 1.3.11 1.2.7
langgraph 0.2.72 1.2.6 1.0.7
openai 1.63.0 2.36.0 2.16.0
anthropic 0.45.2 0.102.0 0.76.0

Still uncaptured: deployed commit SHA per host (git rev-parse HEAD) and the Cloudflare Pages deployment ID for each frontend env.

📎 Evidence
  • Test & Prod deployed versions (valid)uv.lock extracts via awk … | grep … on pw-prod /opt/production/pw-enterprise/uv.lock and /opt/test/pw-enterprise/uv.lock (2026-06-25). Full table in docs/vm-tech-inventory.md. ✅
  • node versionsnode --version: pw-dev v18.17.0, pw-prod v26.2.0. ✅
  • Dev deployed versionslangchain==0.3.18 / langgraph==0.2.72 read from the served dev checkout /home/coder/served/pw-enterprise/uv.lock on pw-dev (2026-06-25). ✅
  • Still pending — git SHA per host and Cloudflare Pages deploy IDs were not captured. 🔍 needs git rev-parse HEAD on each checkout + Pages dashboard. ✅