Commit Graph

4 Commits

Author SHA1 Message Date
9131e83c08 Improve signal quality (Exa news category) and remove mock fallback
Exa harvester:
- EXA_CATEGORY=news (default) restricts to news articles, excluding evergreen
  careers/marketing landing pages that were producing irrelevant signals.
- Event-focused query (acquisition/earnings/launch/leadership), dropped
  hiring/career terms that pulled recruiting pages.
- Domain scoping now OFF by default (broad-web news about the account beats
  first-party careers pages); add EXA_EXCLUDE_DOMAINS and loop --domain-filter.

LLM layer:
- Remove the mock reasoner entirely (no provider => loop refuses to run).
- On HTTP 429, WAIT (LLM_RATELIMIT_WAIT_SECONDS, default 900s; honors
  Retry-After) and retry up to LLM_RATELIMIT_MAX_RETRIES (24) instead of
  degrading to mock output.
- If the LLM is ultimately unavailable for an account, skip it and leave its
  signals unconsumed (retried next run) — never fabricate briefs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 10:41:41 -04:00
2374ef137d Add OpenAI-compatible LLM provider (URL/model/key configurable)
- New provider 'openai' calls any OpenAI-compatible /chat/completions endpoint
  (OpenAI, OpenRouter, Together, Groq, NVIDIA, vLLM, Ollama, ...), set via
  OPENAI_BASE_URL / OPENAI_API_KEY / OPENAI_MODEL. Now the default; auto-detects.
- Robustness for models that degenerate (e.g. Kimi repetition loops): anti-
  repetition sampling (temperature + frequency penalty), and a schema-aware
  retry — call_json(require_keys=...) retries a fresh sample on degenerate or
  unparseable output (LLMRetryable). Relevance requires 'signals', synth 'briefs'.
- response_format=json_object (toggle via OPENAI_JSON_MODE); base URL accepts a
  full /chat/completions URL or a /v1 base.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 10:19:52 -04:00
b4e3ed9d9b Batch LLM calls per account; add 5 pilot accounts
- Relevance filter: evaluate all of an account's signals in one LLM call
  (keyed array, chunked at 8) instead of one call per signal.
- Synthesizer: produce all of an account's briefs in one call (one object
  per capability) instead of one call per capability. ~2 calls/account.
- llm: wrap JSONDecodeError in LLMError so callers fall back to mock instead
  of crashing; disable Gemini thinking (thinkingBudget=0) to stop thinking
  tokens truncating JSON; add 429 backoff.
- accounts: add Booz Allen, Dominion Energy, Hope Gas, Markel, GW Medical
  Faculty Associates (verified domains; CRM tier captured in crmTier).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 18:16:08 -04:00
39a338990f Initial commit: prospecting agent loop MVP
Closed-loop account-intelligence system: harvest -> relevance filter vs.
Capability Library -> synthesize -> score -> deliver -> feedback.

- 40-capability Broadcom + VMware library
- Live Exa.ai news connector with hard free-plan request ceilings
- Provider-agnostic LLM layer (Gemini/Anthropic) with offline mock fallback
- LLM confidence wired into composite scoring + low-confidence floor
- 7-account pilot list

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 11:39:59 -04:00