Skip to content

Review/latest updates#1

Open
ReaganKibet wants to merge 84 commits into
mainfrom
review/latest-updates
Open

Review/latest updates#1
ReaganKibet wants to merge 84 commits into
mainfrom
review/latest-updates

Conversation

@ReaganKibet

@ReaganKibet ReaganKibet commented May 27, 2026

Copy link
Copy Markdown
Collaborator

Note

Medium Risk
New server-side proxies guard secrets and add origin/rate limits, but scoring and lead paths now depend on streaming aggregation and fail-open rate limiting; misconfiguration or stream parsing bugs could break evaluations or allow abuse.

Overview
This branch adds a Vercel serverless /api/* layer so the static frontend can call Ada without exposing secrets: lua-chat proxies Lua with server-side LUA_API_KEY, prefers SSE /chat/stream aggregated back to the legacy { text, steps } shape (fallback to /chat/generate), plus fetch-jd (HTML→text with SSRF blocks) and slack-notify. Shared origin allowlisting and per-IP rate limits (Vercel KV, no-op locally) guard all three routes.

Local dev is aligned via dev-server.mjs (npm run dev on port 3000). vercel.json sets SPA rewrites, security headers, and a 120s function budget for long scores.

Repo hygiene: removes committed .claude/settings.local.json (had approved commands referencing secrets) and expands .gitignore (.env, Claude settings, mock scripts). build.md is rewritten to match the shipped static + proxy architecture; large changes.md, docs/llm.md, fix writeups, sheets-apps-script.gs, email-preview.html, and brand assets under public/ document and support lead logging and email work elsewhere in the branch.

Reviewed by Cursor Bugbot for commit d338383. Bugbot is set up for automated code reviews on this repo. Configure here.

ReaganKibet and others added 28 commits May 26, 2026 09:26
- Adjacent agents: replace gradient icon-box cards with clean editorial rows
  (cream icon square, inline text, thin separators — no "AI template" look)
- CTA section: forest-green TS card + purple Lua card with brand labels and
  specific copy; add "What's your next move?" section header
- Brief card: fix bc-lbl contrast (#9AA39B → var(--ink-soft)), use var(--paper)
  bg for bc-box so content is distinct from wrapper
- callScoreApi: widen tool-result parsing to cover .tool_results, .output, .name
  variants; add step[0] dump to console for diagnosing inconsistency
- Fix restart() crash when #overlay element not present (null guard)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
File contained approved bash commands with API key in plain text.
Added to .gitignore so it never gets committed again.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Scan step.output and step.result directly (not just step.toolResults)
- Shared extractScore() helper validates shape in one place
- Match on any step that contains a valid scoring object, not just by tool name
- Extra console logs: all tool result count + first tool result dump

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tions

Invocation contract now explicit — every message is a programmatic API call.
Ada must call the appropriate tool without asking for more info or responding
in text. Eliminates the 'clarifying question' failure mode seen in smoke test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- netlify/functions/score-jd.js: calls Lua developer AI endpoint directly
  with the scoring system prompt + forced tool_choice. One LLM call instead
  of two (Ada routing + score_jd). Fits comfortably within 26s timeout.
- netlify.toml: set functions timeout = 26
- index.html: callScoreApi() uses score-jd endpoint for text JDs; URL-pasted
  JDs still go through lua-chat (needs scraping path via Ada)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Embeds LUA_AGENT_ID, LUA_API_KEY, SCORING_SYSTEM, and SCORE_ROLE_TOOL
directly in frontend JS. callScoreApi() calls Lua developer AI endpoint
from the browser for text JDs, bypassing Netlify functions entirely to
avoid the 504 timeout caused by the 2-LLM-call chain.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New fetch-jd Netlify function fetches job posting URL server-side
(CORS proxy, no AI, fast). Browser then calls Lua AI directly with
the extracted text — same single-LLM-call path as text JDs.
Eliminates the Ada→scrape_jd→score_jd 3-call chain that caused 504s.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root causes fixed:
1. /developer/ai/generate silently drops tools/tool_choice — tool_use
   never appears in response, score always fails
2. Routing through Netlify proxy causes 504 (Ada skill chain ~20-40s
   exceeds Netlify's 26s limit)

Solution: call Ada's chat/generate endpoint directly from the browser.
No Netlify in the scoring path — no timeout. Ada invokes score_jd skill
server-side with proper AI.generate + tool_choice.

For URL JDs: fetch-jd Netlify function handles CORS (HTML fetch only,
no AI, fast) then browser calls Ada with the extracted text.

Removes SCORING_SYSTEM and SCORE_ROLE_TOOL from frontend — Ada owns
the scoring rubric through her deployed skill.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…DPOINT

LUA_CHAT_ENDPOINT was removed in previous commit but still referenced
in three places (capture_lead, submit_cta, enrichment chat), causing
silent JS errors. Replace all three with ADA_CHAT_URL so all Ada calls
use the same direct browser→chat API path — no Netlify env vars needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
score-role.skill.ts:
- Remove tools/tool_choice from AI.generate — Lua platform drops these,
  causing tool_choice-without-tools Anthropic 400 error (generation_failed)
- Switch to JSON text output: system prompt instructs Claude to return
  a raw JSON object matching the scoring schema
- Add tryParseJson helper + update extractScoringResult to handle both
  tool_use (future-proof) and text JSON responses

index.html:
- Replace static ADA_CHAT_URL with adaSessionUrl(prefix) function
- Each evaluation gets a unique channel=eval-{uuid} — eliminates
  session contamination from prior failed calls (was 53k tokens/call)
- Enrichment chat uses state.enrichUrl (consistent across turns)
- capture_lead and submit_cta get fresh sessions (lead-/cta- prefix)
- Add Authorization header to all Ada calls (was missing on some paths)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… broken

Root cause confirmed: skill's AI.generate() fails with generation_failed
on every call (observed in 30 consecutive logs 09:36–11:06). Even after
removing tools/tool_choice in v1.0.18, still fails. Developer endpoint
tested directly — works perfectly for text + JSON output.

Scoring path: Browser → score-jd.js Netlify → developer AI endpoint
(JSON text output, no tools) → parse JSON → result.
API key stays server-side. 15–20s per call fits within 26s timeout.

Ada chat API still used for capture_lead, submit_cta, enrichment chat
(those are single LLM steps, no nested AI.generate(), work fine).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New /api directory with Vercel function signatures (ESM, req/res):
  * score-jd.js — JSON-via-text via /developer/ai endpoint (no tools/tool_choice
    since runAiGeneration silently drops them); recomputes verdict band on
    score-mismatch correction so verdict + score stay internally consistent
  * lua-chat.js — Ada chat proxy, forwards ?channel= query so the per-call
    session pattern (eval-/enrich-/lead-/cta-<uuid>) survives the proxy hop
  * slack-notify.js — webhook proxy
  * fetch-jd.js — URL scraper with SSRF guard (loopback/RFC1918/AWS metadata)
- Shared origin allowlist in api/_lib/origin.js — reads ALLOWED_ORIGINS env
  plus Vercel's VERCEL_URL / VERCEL_BRANCH_URL / VERCEL_PROJECT_PRODUCTION_URL
- vercel.json: SPA rewrites for /results and /score, security headers
  (X-Frame-Options, X-Content-Type-Options, Referrer-Policy)
- index.html: remove hardcoded LUA_API_KEY/LUA_AGENT_ID, flip all endpoint URLs
  to /api/*, drop client-side Authorization headers (proxy attaches Bearer),
  delete dead scoreViaAda + extractScore helpers
- Delete netlify.toml + netlify/functions/*

Vercel Pro gives 60s function timeout (vs Netlify Pro 26s / Free 10s) which
removes the timeout pressure that motivated the earlier browser-direct revert.

Required env vars on Vercel (Production + Preview):
  LUA_API_KEY, LUA_AGENT_ID, SLACK_LEADS_WEBHOOK_URL, ALLOWED_ORIGINS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- score-jd.js: call Ada's chat API (/chat/generate) not developer endpoint,
  unique eval-{uuid} channel per request prevents session contamination
- lua-chat.js: accept channel from request body for session isolation
- index.html: remove LUA_API_KEY + LUA_AGENT_ID from browser; all Ada calls
  now go through /.netlify/functions/lua-chat (server-side credentials);
  remove scoreViaAda(), adaSessionUrl(); add newChannelId() helper
- src/index.ts: embed full scoring rubric in Ada's persona so she scores
  directly on 'Score this job description:' messages (no score_jd tool call);
  remove scoreRoleSkill from skills array
- scrape-jd.skill.ts: add SSRF guard blocking RFC1918, loopback, link-local,
  metadata endpoints; restrict to https:// only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Project's package.json has 'build: tsc' for the Lua skill workflow.
Vercel auto-runs npm run build on deploy, which tried to invoke tsc
(failed with permission error in their build env, but also unnecessary
— the web deploy is static HTML + api/ JS, no TS compilation needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Adopted Vercel hosting (api/ functions, vercel.json) from lua remote
- api/score-jd.js: updated to call Ada's chat API (/chat/generate) instead
  of the developer AI endpoint — Ada scores directly using her persona rubric
- Conflict resolution: Vercel /api/* endpoints, adaSessionUrl() channel pattern,
  removed client-side LUA_API_KEY/LUA_AGENT_ID and netlify functions
- src/index.ts: Ada's persona now includes full scoring rubric; scores directly
  on 'Score this job description:' messages (no score_jd tool call)
- scrape-jd.skill.ts: SSRF guard blocking RFC1918, loopback, link-local, metadata

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Netlify redirect /api/:name -> /.netlify/functions/:name so index.html's
/api/* calls work on both platforms simultaneously:
- netlify/functions/score-jd.js: Ada chat API, unique eval-{uuid} channel
- netlify/functions/lua-chat.js: channel from ?channel= query string
- netlify/functions/fetch-jd.js: URL scraper with SSRF guard
- netlify/functions/slack-notify.js: webhook proxy
- netlify.toml: redirect rule + static file publish + security headers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re-deployed the agent to restore the inline-rubric persona + skill set
after an accidental overwrite from a stale local push. Persona v20,
capture-lead v1.0.18, submit-cta v1.0.16, ada-chat v1.0.13,
brief-wizard v1.0.13, scrape-jd v1.0.14. score-role correctly absent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Without an explicit outputDirectory, Vercel defaulted to public/ once a
buildCommand was set — so index.html (at the repo root) was 404'd while
api/* functions deployed fine. Point output at . so the static SPA is served.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented May 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
talentsafari Ready Ready Preview, Comment Jun 9, 2026 3:14pm

Request Review

…dlers

Hardens score-jd, lua-chat, fetch-jd, and slack-notify against abuse for the
60k-user launch. The existing isOriginAllowed check only stops casual browser
abuse — curl with a forged Origin trivially bypasses it, and an unbounded loop
against score-jd / lua-chat burns billable Sonnet tokens.

Per-IP limits (stricter of two buckets wins; 429 with Retry-After + JSON body):
- score-jd:     5/min,  30/hour
- lua-chat:    10/min,  60/hour
- fetch-jd:     5/min,  30/hour
- slack-notify: 10/min, 60/hour

Implementation: ZSET-based sliding window in @vercel/kv, atomic MULTI/EXEC
(ZREMRANGEBYSCORE + ZADD + ZCARD + PEXPIRE + ZRANGE) per request. Defensive
parsing tolerates both @upstash/redis ZRANGE WITHSCORES return shapes. Fails
open (allowed:true) if KV env vars are missing or KV throws — better to serve
a real user than 500 the whole site over a rate-limiter outage.

Deploy prerequisite: connect a Redis store to the Vercel project via the
Marketplace (Vercel KV was retired Dec 2024 and migrated to Upstash Redis;
the @vercel/kv client still works, and Upstash injects KV_REST_API_URL +
KV_REST_API_TOKEN automatically). Without these env vars the limiter no-ops.

Note: api/*.js handlers may merge-conflict with Session C if both land.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
yashwardhansable and others added 5 commits June 4, 2026 09:10
Shareable writeup of the phantom rares@heylua.ai bug: symptom, root
cause, the real-lead gate (v1.0.34), and the follow-up moving Data.create
below the gate (v1.0.35, pending deploy).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The score-time call no longer records to Data, so update the tool
description and skill context: Data write + Slack/Sheets/email happen only
for a genuine lead-form submission; score-time and flagged calls return
{ skipped } and do nothing else.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Records the deployed version and marks the bug_fix.md follow-up as live.
v1.0.35 moves Data.create below the real-lead gate so score-time auto-calls
no longer write placeholder records to the evaluations primitive.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add §13 covering the rares@heylua.ai bug, root cause, the two-part fix
(v1.0.34 real-lead gate + v1.0.35 Data.create move), and the live state.
Update the §4 capture_lead description to reflect the gating.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Thin-JD enrichment chat now asks about judgment_complexity,
regulatory_burden, relationship_depth, and system_integration — the four
dimensions that previously got no direct user signal — as one numbered
list, re-asking only the gaps (4-turn cap), then folds the answers into
the JD context for score_jd.

- index.html: rewrite enrichment seed (batch of 4, re-ask gaps); label
  folded answers by dimension in buildEnrichedJd; refresh s-enrich copy;
  render Ada messages with preserved line breaks (pre-wrap) and **bold**.
- src/index.ts: add a scoped "intake / clarification mode" persona
  carve-out legitimizing the questioning; leave the score_jd / capture_lead
  / submit_cta hard triggers and their "never ask" rules unchanged.
- docs/fixes/ada_persona.md: plan/writeup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread index.html
yashwardhansable and others added 4 commits June 4, 2026 14:22
Bring Ada's chat back to the first screen (reverted in d1f3d9a) but wired to
the current enrichment brain instead of the old generic one that shipped with
2be603c:

- s-hero is now an inline Ada chat (greeting + composer); the paste textarea /
  dropzone and the separate s-enrich screen are removed.
- The thin-JD (<20 words) branch calls the existing startEnrichChat() so the
  4 high-leverage dimension questions, **bold**/line-break rendering, and the
  dimension-labeled JD fold remain the single source of truth.
- Detailed JDs (>=20 words) get a quick ack, then go straight to the
  calibration questions.
- Chat panel enlarged (260px -> 440px, wider column, larger text) per the
  "make it bigger / cleaner" UI ask; Sample/PDF are icon-only hover-expand
  buttons inside the composer; sub-headline trimmed.
- loadSample()/handlePdfUpload() retargeted to the composer; enrichEnterSend
  rewired to sendHeroMessage; dead handleScoreClick()/sendEnrichMessage()
  removed; renderScreen resets the chat on s-hero (Back/restart) and on boot.
- Fix restart() null-ref now that #otherRoles is gone; drop the §12 redeploy
  marker since the redesign is shipping again.

Plan: docs/fixes/UI_change.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Iterate on the re-shipped chat-first hero per design feedback:

- Remove the "Free · No signup" eyebrow and trim the sub-headline; shift the
  whole hero block up (margin-top: -40px).
- Merge the messages area and input into ONE bordered chat panel (avatar on the
  left). Reply area is a fixed 300px scroll region; input ~90px below it.
- Turn the input into a rounded pill that floats inside the panel: round
  hover-expand tool icons (sample / PDF) on the left, text in the middle, and a
  circular up-arrow (↑) Send button on the right.
- Auto-grow the composer with its content line-by-line up to a 120px cap
  (COMPOSER_MAX_H), then scroll; collapse back on send / Back / restart, and
  grow to fit PDF-extracted text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add §15 covering the feat/ui_changes re-ship: the chat-first hero merged with
the §14 4-dimension intake brain, the single-panel pill composer (hover-expand
icons + circular ↑ send), the auto-grow behaviour, and the flex/height gotcha.
Mark §11 as superseded and point it at §15. Also folds in the pre-existing §14
intake-mode doc edit that was sitting in the working tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Shift the hero conversation box 10px→30px left (translateX on .hero-chat).
- Enrichment seed (startEnrichChat): Ada now checks whether the brief
  description already names a job title; if not, question 1 becomes "What is
  the job title…?" and the four dimension questions follow as 2–5 (five total),
  otherwise just the four. Judged from the JD preview, no JS detection; the
  4-reply cap is unaffected.
- Document the conditional 5th question in §14.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ReaganKibet and others added 7 commits June 5, 2026 11:18
…implementation

- plan.md: scoped roadmap for 4-feature email + CTA landing slice
- public/: track logo + social assets used by rendered report email
- src/skills/capture-lead.skill.ts: full renderReportHtml inline email body
- email-preview.html: align preview with renderReportHtml output
Read ?cta=lua|tech_safari on load and land directly on the matching CTA
screen (Lua -> s-connect, Talent Safari -> s-brief), prefilling the lead
from name/email/company query params. `cta` alone picks the screen; `rec`
is intentionally unused (Option A). role/score are stashed into
state.result for submit_cta's Slack-ping context.

Also preserve the query string in the initial history.replaceState seed
(line 905) so the deep-link isn't stripped back to '/' before the boot
handler reads it.

Frontend-only: no markup/CSS changes to the landing screens, no new env
vars. Implements plan.md §5 F1-F5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(cta): deep-link report-email CTAs into landing screens
- capture-lead.skill.ts: switch email logos (TS, Lua, 3 social icons) to MIME CID inline attachments so Gmail renders without "display images" click. Five attachments via Resend `attachments` field.
- email-assets.ts: new file holding base64 PNG payloads for the 5 logos.
- submit-cta.skill.ts: F1 fix — gate execute() with no_evaluation_context check; reject calls where scoringResult is fabricated (role_title='Unknown' or score=0). Updates tool description + skill context with explicit precondition.
- changes.md: Phase 3 history appended.
Auto-managed version bumps written by the lua push step ahead of the
production deploy (capture-lead 1.0.36, submit-cta 1.0.32, persona/backup v47).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ersona v39)

State manifest update from the production `lua deploy all` of plan B6 —
production now renders the report email with CTA deep-links.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread api/lua-chat.js
});
const data = await genRes.json();
clearTimeout(fetchTimeout);
return res.status(genRes.status).json(data);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fallback parses non-JSON upstream

Medium Severity

After the streaming path fails, the /chat/generate fallback always calls genRes.json() with no content-type or parse guard, so HTML gateway timeout pages (the failure mode streaming was meant to avoid) throw and surface as a generic 500 instead of a structured error.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 416cf3b. Configure here.

if (done) break;
agg.push(decoder.decode(value, { stream: true }));
}
return agg.finish();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stream decoder never flushed

Low Severity

aggregateStreamResponse decodes chunks with { stream: true } but never performs a final TextDecoder flush after the read loop ends, so UTF-8 code points split across the last chunk can be dropped from aggregated text and tool payloads.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 416cf3b. Configure here.

yashwardhansable and others added 2 commits June 9, 2026 18:03
Real lead-form submissions with short JDs were being skipped by
capture_lead — no Slack body, no Sheets row, no Data record, no report
email — because the gate short-circuited on flags.short_jd. The flag is
LLM-judged and misfired on borderline JDs (a 105-word JD was tagged
short), so genuine leads (Benjamin/GG Mac, Nick/SDR, king/Discord CM)
were lost while only the browser "evaluation starting" ping landed.

Fix #1: drop short_jd from the capture gate; keep non_english /
suspected_fake as the spam guard. Short but real JDs now post to Slack,
append to Sheets, write to Data, and send the report + follow-up email.

Fix #2: make short_jd deterministic — recompute from an actual word
count (<80) in the score_jd wrapper and overwrite the LLM value, killing
borderline false positives.

short_jd is still computed and surfaced as a tag (Slack "⚠️ short JD",
Sheets shortJd column) for downstream eyeballing. Persona / tool
description / skill context updated to match. Phantom-lead protection
(no_lead_details gate) is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread api/lua-chat.js
yashwardhansable and others added 3 commits June 9, 2026 20:13
Add §16 covering the capture_lead short_jd gate fix + deterministic
short_jd, and update the §4 skill notes, scoring-model flags line, and
§10 gotcha so "never post on a flag" reflects spam-flags-only behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the Meta Pixel base code (id 1022960976820763, PageView) in <head>
and fire funnel events from JS as the SPA advances through screens, since
the pixel can't observe .screen transitions on its own:

- StartEvaluation (custom) when scoring kicks off (runAnalysis)
- ViewContent on first verdict reveal (not re-fired on Back-to-verdict)
- Lead on the email-gate submit, alongside the existing LinkedIn fire
- BriefTalentSafari / ConnectLua (custom) + Contact on CTA submit,
  distinguishing the human vs agent path

Events go through guarded fbTrack/fbTrackCustom helpers (typeof + try/catch)
so a blocked or absent pixel script can never break the app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d338383. Configure here.

Comment thread api/lua-chat.js
headers: authHeaders,
body: payload,
signal: controller.signal,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stream errors trigger second agent run

Medium Severity

When the primary /chat/stream call fails or errors after the upstream may have started work, lua-chat falls through to /chat/generate with the same payload. That can run Ada twice for one user action, risking duplicate scoring and duplicate capture_lead side effects.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d338383. Configure here.

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.

7 participants