Feat/edit options quick reply buttons - #131
Open
priyankmodiPM wants to merge 40 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>
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>
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>
* 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>
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>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <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>
…ck-reply-buttons # Conflicts: # src/actions.js # src/app.js # src/express/expressApi.js
* 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
…rored 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.
…comes 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.
…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.
…nt/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.
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.
…ck-reply-buttons # Conflicts: # src/actions.js # src/actions.test.js # src/app.js # src/express/expressApi.js
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.