Feat/flow2 deterministic phone gated - #133
Open
varun6325 wants to merge 43 commits into
Open
Conversation
When an incoming WhatsApp message contains "update the discount", the webhook automatically replies to the sender with the discount image via the WhatsApp Cloud API. Phone number ID and token are read from env vars. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ant (#1) Adds a GPT decision loop (with per-phone conversation history) that routes inbound WhatsApp messages to campaign-graphic actions — listing graphics, checking allowed edits, editing via Adobe Express, and bulk generation from an uploaded file — instead of only replying to a hardcoded "update the discount" phrase. Co-authored-by: Priyank Modi <pmodi@adobe.com>
Co-authored-by: Priyank Modi <pmodi@adobe.com>
yarn.lock resolved every package from Adobe's internal Artifactory (picked up via local ~/.npmrc), which Render's build servers can't reach or validate certs for, causing "unable to get local issuer certificate" during deploy. Regenerated against registry.npmjs.org and dropped package-lock.json since render.yaml only runs yarn. Co-authored-by: Priyank Modi <pmodi@adobe.com>
app.js reads process.env.OPENAI_API_KEY but the Blueprint never declared the key, so a value set in the Render dashboard was never wired into the service, causing "Missing credentials" at boot.
…ails Model was hardcoded to gpt-4o while the configured Azure OpenAI resource only has a gpt-5.4-mini deployment, causing every request to fail with a 404 "deployment does not exist" error. Reads OPENAI_MODEL/OPENAI_BASE_URL from env instead, and logs the resolved config plus full error details on failure to make future mismatches easy to diagnose. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* docs: add design spec for mocked Adobe Express image-edit flow * docs: add implementation plan for image-edit flow * feat: add in-memory tracked-image store * feat: add mock Adobe Express API module * feat: add mock Meta media upload module * feat: extract GPT action handlers and add image-edit validation flow * feat: wire image-edit flow into the webhook and GPT tool schema * feat: map Croma earbuds graphic to Price/Address/Product Image/Partner Logo edits Replaces the New Arrival Poster mock seed image with the real Croma earbuds graphic and its allowed-edit fields. * feat: return fixed updated Croma earbuds image for any edit Any allowed edit on the Croma earbuds graphic now resolves to the fixed croma1-earbuds-updated image, sent as a new WhatsApp message, instead of a randomized mock render/upload URL. --------- Co-authored-by: Priyank Modi <pmodi@adobe.com>
* Add design spec for global fixed edit-flow responses
Whenever an edit is requested, always send the fixed Croma earbuds
image; whenever allowed-edits is asked, always reply with the fixed
layer list. Removes per-template edit-key validation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Add design spec for real Adobe Express API integration
Replaces the mocked expressApi.js/imageStore.js/metaUpload.js flow with
real tagged-documents/generate-variation/status calls against a shared
docID catalog, per the brainstorming session.
* Ignore .superpowers scratch directory
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat: add Adobe IMS token fetch/cache module
Implement expressAuth.js with getAccessToken and buildAuthHeaders functions.
Provides IMS token caching with 60s refresh margin per Adobe IMS v3 convention.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat: read the shared docID catalog instead of hardcoded seed images
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix: validate catalog is an array in loadCatalog()
If the catalog file parses successfully but isn't an array (e.g., `{}` or `42`),
treat it as an invalid catalog, log the error, and return empty array instead of
crashing on `.map()`. Aligns with design spec requirement to degrade gracefully
on catalog read failures.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat: replace mocked Express API with real tagged-documents/generate-variation/status calls
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* feat: wire actions.js to the real Express API and drop mocked edit validation
* feat: log webhook metadata fields and declare Express API env vars
* Fix cross-task issues from final branch review
- Use the real statusUrl returned by generateVariation instead of
reconstructing a status URL from apiBaseUrl()+jobId, which was an
unverified assumption about the API's URL shape.
- Overlay image.currentEdits onto tagged elements before formatting
allowed-edits messages so previously edited fields show their latest
value instead of the stale original document value.
- Narrow the hardcoded campaign graphics list to match the real
single-entry catalog (Croma Earbuds).
- Guard the sendImage call in actionEditGraphic with try/catch so a
delivery failure doesn't swallow an already-successful edit; users
now get a "couldn't send" message instead of no reply at all.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Add implementation plan for real Adobe Express API integration
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Move source files into src/, group Express API modules under src/express/
Keeps data/ (shared catalog) and docs/ at repo root. Updates
imageStore.js's default catalog path, actions.js/actions.test.js's
expressApi import, and the app.js entry point in package.json/render.yaml
to match.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Priyank Modi <pmodi@adobe.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…catalog - Reject edit_graphic requests with a discount field over 40%, telling the user the real cap instead of silently clamping the value. - Instruct GPT to translate tag text into Devanagari script (not transliteration) when the user asks for a Hindi translation. - Rename catalog entry to "Croma Diwali offer" with its correct docId. - Ignore .env locally. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sends "Change heading / price / discount / product" as WhatsApp interactive buttons (or a list message when there are more than 3 options) instead of a plain text message, and handles the incoming button/list tap the same way as free-text input. Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* Always render edit options as native reply buttons Replace the list-picker fallback with additional button messages (3 per message, WhatsApp's per-message cap) so options over 3 still show up as tappable buttons instead of a "Choose a field" dropdown. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Simplify edit-options prompt and button labels Show a short "What would you like to change?" prompt instead of dumping every field's current value into the button message body, and humanize camelCase field names (e.g. discountPercentage -> "Change discount") instead of only stripping _text/_image suffixes. The detailed field listing is still kept in conversation history for GPT context. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Implements Flow 2.2 — creating a brand-new creative from a text description, assembled from approved brand elements, with canned images. - add create_design tool + action; registers a per-phone, in-memory source: 'local' design backed by canned image URLs (data/onam-design.json) - route edit_graphic / check_allowed_edits on image source: local designs skip the Adobe Express API; catalog designs keep the existing Express path - palette guardrail: reject off-palette background edits and offer the approved festive accents (Marigold / Maroon / Deep Green) - Malayalam banner translation via canned image (detect Malayalam script) - tighten tool descriptions + system prompt so messages that carry concrete values route to edit_graphic instead of check_allowed_edits - add one log line per action for observability - tests: cover create/edit/guardrail/translation; update stale expectations Co-authored-by: varun kalra <varkalra@adobe.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Supports the simplified Anjali flow (create -> add address -> translate to Malayalam) and fixes the case where "translate the banner to Malayalam" was rejected by the palette guardrail. - editLocalDesign: a Malayalam/translate request now short-circuits and maps straight to the Malayalam creative, bypassing the locked-field and palette guardrails (the model may place the translated text on any key, including one that looks like "background") - detect a translation request from Malayalam script or the word "Malayalam" in any edit key/value; mark language so resolveLocalImage picks the Malayalam image regardless of the edit key used - address-only edits still resolve to the final image - tests: cover address-only -> final, translate via unrecognized key, Malayalam under any key, and the background-key regression Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Always render edit options as native reply buttons Replace the list-picker fallback with additional button messages (3 per message, WhatsApp's per-message cap) so options over 3 still show up as tappable buttons instead of a "Choose a field" dropdown. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Simplify edit-options prompt and button labels Show a short "What would you like to change?" prompt instead of dumping every field's current value into the button message body, and humanize camelCase field names (e.g. discountPercentage -> "Change discount") instead of only stripping _text/_image suffixes. The detailed field listing is still kept in conversation history for GPT context. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Wire quick-reply button taps to the actual field/image being edited Button/list-row ids now encode edit:<imageId>:<fieldName> instead of just a display title, so tapping an edit option tells GPT precisely which field to edit instead of a truncated, ambiguous label. GPT now asks for the missing value and applies it via edit_graphic once supplied, rather than never reaching the Express API. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add design doc for TV product-swap quick-reply flow Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add implementation plan for TV product-swap quick-reply flow Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Extract interactive-reply id parsing into a testable module * Support fully-specified multi-field edits in interactive reply ids * Add actionSelectTvModel handler for the TV product-swap quick replies * Wire select_tv_model GPT tool into the webhook handler --------- Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…-routing Fix/onam malayalam translate routing
The two flows now live in their own files so changing one cannot affect the other; actions.js is a thin router that dispatches deterministically on image.source. No behavior change (all tests pass). - expressFlow.js: Flow 1 (source: 'express') — Adobe Express catalog designs (checkAllowedEdits, editGraphic, selectTvModel, discount cap) - localFlow.js: Flow 2 (source: 'local') — canned-image designs (createDesign, checkAllowedEdits, editGraphic, palette + Malayalam handling) - editOptions.js: shared pure presentation helpers (buildEditOptions, formatAllowedEdits), extracted so neither flow depends on the other; expressApi re-exports them for backward compatibility - actions.js: thin dispatcher only (resolve image → route by source) - tests mirror the modules: expressFlow.test.js + localFlow.test.js, with a small actions.test.js for router/dispatch behavior - docs/diagrams: mermaid flowcharts for both flows Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…l-flows refactor: split the two edit flows into self-contained modules
…ions
Implements the dealer-guided local flow: describe products+offer → assistant
suggests Onam → asks to add address → generates the creative → offer to change
→ translate to Malayalam. Uses only the onam-final and onam-malayalam creatives.
- ask_for_more_information can now carry options (e.g. ["Yes","No"]) rendered as
tappable WhatsApp reply buttons; the tapped title flows back as the user's text
- create_design takes includeAddress; when true the with-address ("final")
creative is sent (records the address so later edits keep that state)
- images are now sent WITH a friendly caption describing the offer / the change,
so text + image arrive together like a real promo
- widen the GPT context window (last 3 → last 12) so multi-step follow-ups retain
the original product/offer request; system prompt drives the guided flow
- tests: cover includeAddress → final image, captions, and button-reply parsing
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…delay Generation no longer returns instantly. create_design and the local edit path now stream progress messages one at a time (with a tunable pause) before sending the image, so it feels like real work. - streamProgress() sends step messages with a GEN_STEP_DELAY_MS pause (default 1800ms); no-op when no sendText is provided, so unit tests stay instant - create streams: creating → pulling brand kit → adding products → applying offer/styling → (if chosen) placing address, then the image - Malayalam edit streams: translating → re-rendering, then the image - messages are dynamic (name the actual products/offer; address step only when address was requested) - sendText is threaded through actions → both flows; app.js drops the old static pre-step texts; expressFlow shows a single guarded re-render notice - demo-onam-flow.sh waits for generation before the next step (GEN_PAUSE) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e the image
WhatsApp delivers link images a beat after plain text, so a follow-up sent as a
separate message after the image ("Want to change anything?" / "Anything else?")
was showing up before the image.
- fold the follow-up prompt into the image caption for create and edit success
paths; the flow sends the image+caption and returns { skipSend, historyText }
so app.js no longer sends a separate (racing) text
- app.js create_design/edit_graphic handle the string-vs-object return like
check_allowed_edits already does; guardrail rejections still return a string
- apply the same caption treatment to the express edit path (latent race)
- tests updated for the new return shape / caption assertions
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feat/local guided create flow
) * Always render edit options as native reply buttons Replace the list-picker fallback with additional button messages (3 per message, WhatsApp's per-message cap) so options over 3 still show up as tappable buttons instead of a "Choose a field" dropdown. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Simplify edit-options prompt and button labels Show a short "What would you like to change?" prompt instead of dumping every field's current value into the button message body, and humanize camelCase field names (e.g. discountPercentage -> "Change discount") instead of only stripping _text/_image suffixes. The detailed field listing is still kept in conversation history for GPT context. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Wire quick-reply button taps to the actual field/image being edited Button/list-row ids now encode edit:<imageId>:<fieldName> instead of just a display title, so tapping an edit option tells GPT precisely which field to edit instead of a truncated, ambiguous label. GPT now asks for the missing value and applies it via edit_graphic once supplied, rather than never reaching the Express API. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add design doc for TV product-swap quick-reply flow Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Add implementation plan for TV product-swap quick-reply flow Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Extract interactive-reply id parsing into a testable module * Support fully-specified multi-field edits in interactive reply ids * Add actionSelectTvModel handler for the TV product-swap quick replies * Wire select_tv_model GPT tool into the webhook handler * Add design doc for Edit Product/Discount/Price menu with Hinglish-mirrored replies Specifies the fixed 3-button menu, WhatsApp list picker, generalized discount-cap validation, and GPT-phrased language-mirrored responses requested for the Express-catalog edit flow. * Generalize discount cap to price edits and return structured edit outcomes editExpressDesign now rejects any price edit implying more than 40% off (not just literal "discount" fields), with rounding tolerance for whole-rupee prices, and returns structured outcome objects instead of hardcoded reply strings so the caller can phrase the final reply. * Replace dynamic edit menu with fixed Edit Product/Discount/Price for Express-catalog images Express-catalog graphics now always show the same 3-option menu instead of a per-document field list, so choosing what to edit no longer needs an Express API round trip. Local/Onam-style designs are unaffected. * Present TV model picker as a list with Choose product button * Add WhatsApp list-message support for the product picker * Add GPT-phrased, language-mirrored edit replies and bare-field discount/price routing Express-catalog edit outcomes are now phrased by a second GPT call that mirrors the user's language style (English or Hinglish), and the fixed menu's discount/price bare fields get explicit system-prompt rules for computing a new price from a requested discount percentage. * Add implementation plan; amend spec with discount-cap rounding tolerance The spec's cap check needed a rounding-tolerance clause: whole-rupee price rounding means an at-cap request never implies exactly 40.0000%, so a strict > 40 check would reject the script's own 40%-cap example. --------- Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
selectTvModel encoded the same imageId + shared TV_MODEL_EDITS into every option id, so all 3 WhatsApp list rows (Sony/LG/Samsung) got an identical id. WhatsApp rejects list messages with duplicate row ids (400 #131009), so the picker never reached the user. buildValueEditId now accepts an optional discriminator (the model title) so ids stay unique while still resolving to the same edits on tap. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adobe's generate-variation API only accepts pre-signed image URLs from AWS/Dropbox/Azure (windows.net) for tagMappings; the Scene7 CDN URL was rejected, causing the Sony Bravia edit to fail against the real Express API. Also export the constant so the test doesn't hardcode a copy that'll drift when the URL is next rotated. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swapping the placeholder image to a long pre-signed S3 URL made selectTvModel's row ids ~2000 chars (encoded edits round-trip through both the WhatsApp row id and the GPT-facing message text), which WhatsApp rejects with #131009 "Row id is too long. Max length is 200." Encode a short token in place of the real URL, and expand it back to the actual S3 URL in editGraphic right before it reaches the Express API, so nothing WhatsApp- or GPT-facing carries the full URL. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tton emojis The edit_graphic success caption was a GPT-phrased one-liner; replace it with the actual Diwali banner promo copy (with the updated price baked in) so the message reads like real product marketing. Also pause briefly before sending the follow-up edit-menu buttons — WhatsApp delivers link-image messages a beat after text/interactive ones, so the buttons could arrive first even though the image is awaited first in code. Add emojis to the 3 fixed edit-menu buttons. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adobe's Express API rejects a JSON number for a text tag with "Unsupported text value for tag: price" (422) — price/oldPrice are the first numeric edit fields this bot computes, so this only surfaced now.
Reworks the local (canned) flow from the Onam festive design into the dealer→customer personalised offer story: a salesman creates an on-brand, personalised insurance offer for a specific customer, then localises it. - data/offer-design.json replaces onam-design.json: two canned creatives (English banner-apoorva, Hindi banner-apoorva-hindi), the HQ-approved plans, and the featured plan's price floor for governance - localFlow: createDesign now takes customer/model/plan/includeContact, streams personalised progress, and sends the English creative; editGraphic resolves English↔Hindi (robust: Devanagari OR the word "Hindi" under any key); language is the only editable slot (brand/price/plan locked) - app.js: create_design schema + system-prompt guidance rebuilt for the guided offer flow (plan picker → add contact? → anything else? → create), with the HQ price-floor governance injected from the design data so GPT refuses below-floor pricing; robust to phrasing variations - getOfferContext() surfaces plans + governance to the prompt - tests rewritten for the auto flow (create/caption/streaming, EN↔HI, governance context, router dispatch); 60 passing - demo-auto-flow.sh drives the full conversation (plan tap → contact → anything else → generate → governance refusal → translate to Hindi) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cepts
With tool_choice:'required', tapping "Keep it" made GPT re-fire the same
price-floor explanation. Add explicit guidance: an acceptance ("Keep it") is a
brief acknowledgement via ask_for_more_information (no options) — never a repeat
of the governance message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- remove the insurance-amount governance beat (plan/price refusal + "Keep it") from the create flow — not needed - merge "Adding the <model>…" and "Applying the approved <plan> plan…" into one streaming line to cut a message - demo-auto-flow.sh: remove the governance steps (generate → translate to Hindi) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…elivery Switch the offer banner URLs to https:// and drop ?cache=off. WhatsApp needs https for link media, and cache-busting forced a slower origin fetch — together the likely cause of intermittent missing images. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore the cache-busting query param (still on https) per preference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feat/auto insurance flow
* fix(express): update discountPercentage tag alongside price on discount edits Discount edits were only computing and setting price, leaving the document's discountPercentage tag stale even though the price had changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(express): auto-generate the TV product image S3 URL instead of a hardcoded one The previous presigned S3 URL for the TV placeholder image was hand-generated and expired after ~12h, requiring manual regeneration. Now the Scene7 source image is downloaded and re-uploaded to S3 on demand (ported from dynamicmedia-autoreflow's ImageS3Uploader), so the presigned URL is always fresh. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* fix(express): update discountPercentage tag alongside price on discount edits Discount edits were only computing and setting price, leaving the document's discountPercentage tag stale even though the price had changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(express): auto-generate the TV product image S3 URL instead of a hardcoded one The previous presigned S3 URL for the TV placeholder image was hand-generated and expired after ~12h, requiring manual regeneration. Now the Scene7 source image is downloaded and re-uploaded to S3 on demand (ported from dynamicmedia-autoreflow's ImageS3Uploader), so the presigned URL is always fresh. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(deps): resolve new AWS SDK packages from the public npm registry yarn.lock pointed at Adobe's internal Artifactory host for the new @aws-sdk packages, picked up from this machine's global npm registry override. That's only reachable/trusted on Adobe's network — Render's build container has no CA trust for it, so `yarn install --frozen-lockfile` failed there with "unable to get local issuer certificate". Re-resolved against registry.yarnpkg.com to match the rest of the lockfile. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…e7 (#17) Appends &fmt=png-alpha to the Scene7 SonyTv URL so the downloaded source image keeps transparency before it's re-hosted on S3. Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…pacing Flow 2's Yes/No follow-ups and the "Change X" edit-menu button now carry emojis, matching the express flow's existing style. Plan-picker buttons stay plain text — prefixing them pushed titles like "Engine Protect combo" past WhatsApp's 20-char reply-button cap (#131009 API error). Also slows the streamed "generating..." progress messages (1800ms -> 3500ms per step) so the final banner takes longer to arrive and feels more like real generation work, and bumps the demo script's wait accordingly.
…and-slower-generation feat(local): emoji-prefixed Yes/No + edit buttons, slower generation …
…skip live Express/S3 calls (#19) Product-image swap requests (select_tv_model) now bypass the real Adobe Express generate-variation pipeline and S3 re-hosting entirely, returning a pre-rendered banner URL instead. The usual "calling Express API" progress message still streams to the user. Price/discount-only edits are unaffected and continue to hit the real Express API. Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…20) "discountPercentage" (sent by GPT alongside the computed price per the system prompt) isn't a tagged document field, so every discount edit was being rejected as disallowed_fields before the discount-cap logic ever ran — e.g. "thik hai 40 hi kardo" always failed. editGraphic now recognizes discountPercentage explicitly: requests over the 40% cap still return discount_capped, and everything else returns the hardcoded Croma-Diwali-Banner-discount-update banner (same pattern as the earlier product-update bypass), still showing the usual Express progress message. Co-authored-by: Priyank Modi <pmodi@adobe.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Take the plan → contact → confirm → create sequence out of the LLM's hands and drive it from a code state machine, so the questions always get asked in order instead of the model sometimes jumping straight to creating. - flow2Session.js: pure state machine (start/advance) returning ask/reask/create descriptors; app.js owns the WhatsApp side effects. While a session is active the LLM is bypassed entirely. - fuzzy.js: typo-tolerant matching (Levenshtein) for plan and yes/no answers, so a tapped button OR a mistyped reply both resolve; unmatched answers re-ask. - Gate Flow 2 to a single demo phone (FLOW2_PHONE, default 9899860983, substring match). Other numbers are restricted to the current behaviour (Flow 1 + generic tools); a stray create_design there is politely declined. - Deterministic fuzzy trigger (isCreateOfferIntent) detects a "create a personalised offer" message without the LLM and (re)starts the session from step 1 — checked before the in-progress bypass so a re-prompt restarts cleanly. - extractOffer pulls customer/model from the trigger text, falling back to defaults in offer-design.json. - The LLM's only Flow-2 role is now intent detection + entity extraction; system prompt and create_design schema updated to match. Flow 1 logic is untouched; it's now safer since arbitrary numbers can't trigger Flow 2. Adds fuzzy.test.js + flow2Session.test.js (82 tests pass).
Lower the default pause between streamed "generating…" progress messages so the banner arrives faster. Still env-tunable via GEN_STEP_DELAY_MS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.