Repository navigation
Register Zendesk + support endpoint config for Contact us - #6548
Conversation
There was a problem hiding this comment.
Summary
Enables MIT Learn’s frontend to call a new environment-specific support agent endpoint. Adds placeholder Zendesk configuration across Learn AI environments so support intake can be configured without changing deployments.
Key Changes
- Configures CI, QA, and production frontend support-agent endpoints.
- Exposes the support endpoint through Next.js public runtime configuration.
- Adds per-environment Zendesk API and custom-field placeholders for support intake.
All Relevant File Changes (click to expand)
- src/ol_infrastructure/applications/learn_ai/Pulumi.CI.yaml: Adds unset Zendesk API and custom-field configuration placeholders.
- src/ol_infrastructure/applications/learn_ai/Pulumi.Production.yaml: Adds unset Zendesk API and custom-field configuration placeholders.
- src/ol_infrastructure/applications/learn_ai/Pulumi.QA.yaml: Adds unset Zendesk API and custom-field configuration placeholders.
- src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.CI.yaml: Configures the CI support-agent endpoint.
- src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.Production.yaml: Configures the production support-agent endpoint.
- src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.QA.yaml: Configures the QA support-agent endpoint.
- src/ol_infrastructure/applications/mit_learn_nextjs/main.py: Publishes the support endpoint as a Next.js public environment variable.
💬 Feedback & Commands
Share feedback on my comments with 👍 👎 — I'll stop raising issues you push back on. Think I missed something? Adjust my sensitivity →
5 things I can do →
#optibot review— I'll re-review your latest changes (incremental)#optibot full review— I'll re-review the entire PR from scratch#optibot fix— I'll apply my suggested fixes to your code#optibot compliance— I'll run a compliance check on your changes#optibot release notes— I'll write up release notes for your production release
💡 Tip: Add repo-specific conventions that I'll apply to every review — Review Memory.
- 🔄 re-review this PR
There was a problem hiding this comment.
Summary
Enables the Learn frontend’s support-agent integration, allowing users to submit support requests through environment-specific AI endpoints. Configures Zendesk intake settings for QA while preserving unset placeholders in CI and production until credentials and instance-specific field IDs are available.
Key Changes
- Exposes environment-specific support-agent endpoints to the Learn frontend.
- Configures QA to submit support requests to its Zendesk sandbox.
- Keeps CI and production support integrations disabled until Zendesk settings are provisioned.
All Relevant File Changes (click to expand)
src/ol_infrastructure/applications/learn_ai/Pulumi.CI.yaml: Adds unset Zendesk endpoint and custom-field placeholders.src/ol_infrastructure/applications/learn_ai/Pulumi.Production.yaml: Adds unset Zendesk endpoint and custom-field placeholders.src/ol_infrastructure/applications/learn_ai/Pulumi.QA.yaml: Configures QA Zendesk sandbox endpoint and instance-specific field IDs.src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.CI.yaml: Adds the CI support-agent endpoint.src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.Production.yaml: Adds the production support-agent endpoint.src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.QA.yaml: Adds the QA support-agent endpoint.src/ol_infrastructure/applications/mit_learn_nextjs/__main__.py: Passes the configured support endpoint to frontend runtime configuration.
💬 Feedback & Commands
Share feedback on my comments with 👍 👎 — I'll stop raising issues you push back on. Think I missed something? Adjust my sensitivity →
5 things I can do →
#optibot review— I'll re-review your latest changes (incremental)#optibot full review— I'll re-review the entire PR from scratch#optibot fix— I'll apply my suggested fixes to your code#optibot compliance— I'll run a compliance check on your changes#optibot release notes— I'll write up release notes for your production release
💡 Tip: Add repo-specific conventions that I'll apply to every review — Review Memory.
There was a problem hiding this comment.
🟢 Approval recommended
The additive configuration matches application contracts, covers all three stacks, and preserves feature-flag gating with no blocking issues identified.
No open issues 🎉
What changed in this PR
Registers configuration for the Contact us support flow between mit-learn and learn-ai. Ticket filing remains dependent on Zendesk credentials and configuration being completed before feature-flag activation.
Changes:
- Configures learn-ai QA with the Zendesk sandbox URL and custom field IDs.
- Adds explicit unset Zendesk defaults for CI and Production.
- Registers support endpoints in all three Next.js stacks and exposes them through
NEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINT.
| File | Description |
|---|---|
src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.QA.yaml |
Adds the RC support endpoint. |
src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.Production.yaml |
Adds the Production support endpoint. |
src/ol_infrastructure/applications/mit_learn_nextjs/Pulumi.CI.yaml |
Adds the CI support endpoint. |
src/ol_infrastructure/applications/mit_learn_nextjs/__main__.py |
Maps support configuration to the public environment variable. |
src/ol_infrastructure/applications/learn_ai/Pulumi.QA.yaml |
Sets sandbox Zendesk values and documents instance matching. |
src/ol_infrastructure/applications/learn_ai/Pulumi.Production.yaml |
Adds unset Zendesk defaults and per-instance guidance. |
src/ol_infrastructure/applications/learn_ai/Pulumi.CI.yaml |
Adds unset Zendesk defaults and per-instance guidance. |
Review effort: Balanced
…ction Production Zendesk is not configured yet -- AI_ZENDESK_API_URL is empty, the three custom-field ids are "0", and no OAuth credentials exist outside QA. A production build would ship a launcher that holds a full conversation and then fails at send. The MFE gate is build-time, so there is no runtime switch to pull it back: the fix would be another build and another CI->QA->Prod promotion. Shipping rc-only costs nothing, since rc is where the verification pass happens anyway, and leaves one line to restore once #6548 lands. Refs hq#14033
The Contact us intake (hq#13712) is merged in learn-ai and mit-learn but
does nothing in a deployed environment: no AI_ZENDESK_* setting exists in
any stack, and the launcher's endpoint was never registered.
The Zendesk keys land as placeholders holding their own "unset" defaults,
so this deploys as a no-op until someone fills them in. They are spelled
out rather than left absent so the values have an obvious home and the
per-instance warning sits next to them. Empty is not an option for the
field ids: get_int("") raises at import and would crashloop the pod, so
the sentinel is "0", which _custom_fields already skips.
support_endpoint carries real values -- it follows the same shape as its
three sibling agent endpoints, and mit-learn's gate renders nothing until
NEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINT is set. Added to all three stacks
together because the siblings use require(), so a stack missing the key
fails its own deploy.
CORS_ALLOW_ORIGINS is deliberately untouched. An empty list makes
check_origin a no-op; a non-empty one turns it on for every bot in the
environment, which would 403 any origin not enumerated. It is not needed
for the mit-learn mount (same-site) and belongs with the edX MFE work.
Refs hq#13991
QA uses the odl1791467332 sandbox, the same instance local development files against, so RC can exercise real ticket filing once the matching OAuth credentials land in the SOPS secrets file. CI and Production keep their unset defaults until each gets its own instance.
Encrypt AI_ZENDESK_OAUTH_CLIENT_ID and AI_ZENDESK_OAUTH_CLIENT_SECRET into the learn_ai QA SOPS file. They are issued by the odl1791467332 sandbox that the QA stack's AI_ZENDESK_API_URL points at, and reach the pod through the existing VSO sync (includes=["*"]).
bdb677e to
e6892ad
Compare
What are the relevant tickets?
Refs https://github.com/mitodl/hq/issues/13991, under https://github.com/mitodl/hq/issues/13712
Description (What does it do?)
The Contact us support intake is merged in learn-ai (mitodl/learn-ai#98) and approved in mit-learn (mitodl/mit-learn#4139), but it does nothing in a deployed environment: no
AI_ZENDESK_*setting exists in any stack, and the launcher's endpoint was never registered anywhere in this repo.AI_ZENDESK_API_URLand the three Zendesk custom field ids at theodl1791467332sandbox, the instance local development already files against.nextjs:support_endpoint, wired toNEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINT.The OAuth client id and secret are not here: they are secrets, and belong in
src/bridge/secrets/learn_ai/secrets.{qa,production}.yamlvia SOPS.Implementation details
The Zendesk keys are spelled out in CI and Production rather than left absent so the values have an obvious home and the per-instance warning sits next to them. Those two stacks are unchanged in behavior: the committed values reproduce the defaults in learn-ai's
main/settings.py."0"rather than""for the unset field ids is load-bearing.get_intraisesEnvironmentVariableParseExceptionon an empty string, which would crashloop the pod at import.0is the sentinel_custom_fieldsalready filters on (if field_id and value), so an unconfigured id is dropped from the payload rather than sent to Zendesk.Field ids are minted per Zendesk instance and must not be copied between environments. Zendesk rejects the entire ticket for an id it does not recognise, whereas an unset one only drops that one value. The OAuth credentials are part of the same matched set: the token is minted at
{AI_ZENDESK_API_URL}/oauth/tokens, so QA's client id and secret have to be issued by theodl1791467332sandbox and not by another instance.AI_ZENDESK_URLis a different setting and is deliberately untouched. It is the help center the syllabus/tutor bots link to when no article answers, defaulting tohttps://support.learn.mit.edu, and its hardcoded category ids belong to that help center. QA therefore reads articles from one Zendesk and files tickets into another, which is intended.support_endpointcarries real URLs rather than placeholders: it is not a secret, and it follows the same shape as the three sibling agent endpoints already in these stacks./ai/http/support_agent/is already served by the existingpassauthwildcard route (paths=["/ai/*"]), so no routing change is needed. It is added to all three stacks together because the siblings userequire(), so a stack missing the key fails its own deploy.CORS_ALLOW_ORIGINSis deliberately untouched. It is currently unset for learn-ai in every environment, which makescheck_origina no-op. Setting it to a non-empty list activates theorigin not in allowedbranch for every bot in that environment, so any origin not enumerated starts returning 403, tutor and syllabus chat included. It is not needed for the mit-learn mount, which is cross-origin but same-site, and belongs with the edX MFE work instead.How can this be tested?
Two stacks change. A reviewer with credentials can confirm the shape of each:
The four added env vars should be the only change to the learn-ai pod spec. CI and Production commit the values the application already defaults to, so behavior there is unchanged. QA is the one stack with real values, and even there nothing files: with no
AI_ZENDESK_OAUTH_*in the SOPS secrets file the token POST fails and the bot returns "could not file" — the same outcome as before this PR.The mit-learn half does change something once deployed. mitodl/mit-learn#4139 merged this morning, so
ContactUsLauncherGateis onmainandisContactUsEnabled()readsNEXT_PUBLIC_LEARN_AI_SUPPORT_ENDPOINTdirectly. Setting it satisfies one of the gate's three conditions; the launcher still renders nothing until the PostHogcontact-usflag is on.I did not run either preview — no stack credentials. End-to-end filing can't be exercised from this PR either; it needs the OAuth pair, which isn't here.
Additional Context
Order matters after this merges, because the launcher appearing before Zendesk is configured gives a learner a working chat whose send fails:
AI_ZENDESK_OAUTH_CLIENT_IDand_SECRETto the SOPS secrets file, issued by the same Zendesk instance the stack'sAI_ZENDESK_API_URLpoints at. The VSO sync usesincludes=["*"], so no policy orenvFromchange is needed.AI_ZENDESK_API_URLand the three field ids, each taken from that environment's own Zendesk instance.contact-usflag for that environment.AI_ZENDESK_STUB_MODEis left unset (defaults off) on purpose. Turning it on returnsSTUB-XXXXXXXXand files nothing, which is useful for exercising the conversation on RC but tells learners a ticket was filed when none was.