feat(thrive): add Thrive Learning integration (47 tools + block)#5214
Conversation
Add a full Thrive Learning (LMS) integration covering the public REST API: users lifecycle, audiences with members/managers, assignments and enrolments, completions, content and activity records, CPD, tags, and skills. Uses HTTP Basic auth (Tenant ID + API key) with a region selector for the v1/v2 hosts.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
@greptile |
|
@cursor review |
PR SummaryMedium Risk Overview 47 API tools are added under Docs and catalog updates include Reviewed by Cursor Bugbot for commit 9df1e68. Configure here. |
Greptile SummaryAdds a complete Thrive Learning (LMS) integration with 47 tools covering the full public API surface — user lifecycle, audiences, assignments, enrolments, completions, content, activities, CPD, tags, and skills — plus a block with 47-operation dropdown and region selector. A shared
Confidence Score: 5/5Safe to merge. All 47 tools follow established integration patterns, credentials are handled correctly with user-only visibility, and the previously flagged silent-fallback issues in parseThriveArray and additionalFields have been resolved. The integration is thorough and internally consistent. Auth is correctly built using HTTP Basic over HTTPS in all tools, JSON parsing throws on bad input rather than silently degrading, and the block conditions and required-field mappings align with tool parameter definitions across all 47 operations. The one remaining edge case — parseThriveArray wrapping non-array valid JSON in a single-element array — surfaces as an API-level error rather than silently corrupting data, so it carries no merge risk. apps/sim/tools/thrive/utils.ts — the parseThriveArray fallback path that wraps non-array parsed values. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant U as User / LLM
participant B as ThriveBlock
participant F as Sim Framework
participant T as Thrive Tool (e.g. create_user)
participant A as Thrive REST API
U->>B: Select operation + fill inputs
B->>F: config.tool() → "thrive_create_user"
B->>F: "config.params() → {page: Number, sso: bool, status: …}"
F->>T: Merge block inputs + config.params overrides
T->>T: getThriveBaseUrl(host, "v2")
T->>T: getThriveHeaders(tenantId, apiKey) → Basic auth
T->>T: body() – parseThriveJsonObject / parseThriveArray
T->>A: HTTPS request (GET/POST/PATCH/DELETE)
A-->>T: JSON response (or empty body for DELETEs)
T->>T: parseThriveResponse() – throws on non-2xx
T-->>F: "{ success, output }"
F-->>U: Tool output
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant U as User / LLM
participant B as ThriveBlock
participant F as Sim Framework
participant T as Thrive Tool (e.g. create_user)
participant A as Thrive REST API
U->>B: Select operation + fill inputs
B->>F: config.tool() → "thrive_create_user"
B->>F: "config.params() → {page: Number, sso: bool, status: …}"
F->>T: Merge block inputs + config.params overrides
T->>T: getThriveBaseUrl(host, "v2")
T->>T: getThriveHeaders(tenantId, apiKey) → Basic auth
T->>T: body() – parseThriveJsonObject / parseThriveArray
T->>A: HTTPS request (GET/POST/PATCH/DELETE)
A-->>T: JSON response (or empty body for DELETEs)
T->>T: parseThriveResponse() – throws on non-2xx
T-->>F: "{ success, output }"
F-->>U: Tool output
Reviews (6): Last reviewed commit: "fix(thrive): split status into context-s..." | Re-trigger Greptile |
Greptile SummaryAdds a full Thrive Learning integration with 47 tools covering user lifecycle (v2), audiences, assignments, enrolments, completions, content, activities, CPD, tags, and skills — plus a block with conditional subblock UI, a region dropdown, and 8 template suggestions.
Confidence Score: 3/5Two get-by-ID endpoint paths deviate from the plural base paths used by every other get/list pair in this integration; if those paths are wrong, those tools will 404 on every call without any indication of misconfiguration. The integration is large and mostly well-structured, but apps/sim/tools/thrive/get_user_by_id.ts and apps/sim/tools/thrive/get_activity.ts need the URL paths verified against the Thrive API spec before this is merged. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as Block UI
participant Executor as GenericBlockHandler
participant Utils as tools/utils.ts
participant ThriveAPI as Thrive REST API
UI->>Executor: params (operation, tenantId, apiKey, host, ...)
Executor->>Executor: "resolve tool ID via thrive_${operation}"
Executor->>Executor: coerce numeric/boolean fields via config.params()
Executor->>Utils: executeTool(toolId, finalInputs)
Utils->>Utils: "build URL (getThriveBaseUrl v1|v2 + path)"
Utils->>Utils: build headers (Basic btoa(tenantId:apiKey))
Utils->>Utils: "build body (JSON.stringify object | pass-through string)"
Utils->>ThriveAPI: HTTP request (GET/POST/PATCH/DELETE)
ThriveAPI-->>Utils: Response (JSON or empty body)
Utils-->>Executor: "transformResponse() → { success, output }"
Executor-->>UI: typed output fields
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as Block UI
participant Executor as GenericBlockHandler
participant Utils as tools/utils.ts
participant ThriveAPI as Thrive REST API
UI->>Executor: params (operation, tenantId, apiKey, host, ...)
Executor->>Executor: "resolve tool ID via thrive_${operation}"
Executor->>Executor: coerce numeric/boolean fields via config.params()
Executor->>Utils: executeTool(toolId, finalInputs)
Utils->>Utils: "build URL (getThriveBaseUrl v1|v2 + path)"
Utils->>Utils: build headers (Basic btoa(tenantId:apiKey))
Utils->>Utils: "build body (JSON.stringify object | pass-through string)"
Utils->>ThriveAPI: HTTP request (GET/POST/PATCH/DELETE)
ThriveAPI-->>Utils: Response (JSON or empty body)
Utils-->>Executor: "transformResponse() → { success, output }"
Executor-->>UI: typed output fields
Reviews (2): Last reviewed commit: "feat(thrive): add Thrive Learning integr..." | Re-trigger Greptile |
- parseThriveArray/parseThriveJsonObject now throw a descriptive error on malformed JSON instead of silently sending an empty/omitted value - additionalFields parse errors are surfaced to the caller - remove the redundant 'limit' query param (perPage already covers paging and the API prioritises perPage over limit) from the five list tools and block
|
@greptile I've pushed 47a2c42 addressing the review: |
…ParamId The block test forbids reusing a canonicalParamId across different operation conditions. Replace the two canonical status subblocks (search_users vs list_enrolments) with one 'status' dropdown whose options are labelled by context, fixing the canonical-pair validation failures.
|
@greptile |
|
@cursor review |
Addresses review feedback that one shared status dropdown mixed user lifecycle values (active/inactive/expired/new) with enrolment values (archived/complete/open/...). Use separate userStatus and enrolmentStatus dropdowns (no canonicalParamId) remapped to the tool's 'status' param so each operation only offers valid options.
|
@greptile latest is 9df1e68 — split the shared status dropdown into context-specific userStatus/enrolmentStatus fields per your/Cursor's feedback. Please re-review the latest commit. |
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 9df1e68. Configure here.
Summary
Adds a complete Thrive Learning (LMS) integration covering the full public REST API.
ThriveBlockMetawith 8 templates.user-onlycredentials). No file endpoints exist in this API, so no file handling is needed.Notes
/rest/v2; everything else/rest/v1.utils.tsbuilds the base URL/auth headers and tolerantly parses responses (handles empty-body deletes and JSON error bodies).Validation
tsc --noEmitclean (0 errors)biome lintcleancheck:api-validationpasses