chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,78 @@
import type { ThriveAddUsersResponse, ThriveAudienceManagersParams } from '@/tools/thrive/types'
import { THRIVE_ADD_USERS_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const addAudienceManagersTool: ToolConfig<
ThriveAudienceManagersParams,
ThriveAddUsersResponse
> = {
id: 'thrive_add_audience_managers',
name: 'Thrive Add Audience Managers',
description: 'Add managers to a Thrive audience with their permissions.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
managers: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'JSON array of manager objects (1-100). Each: {"reference":"user@example.com","permissions":{"audienceManager":{"manageContent":true,"assignments":true},"peopleManager":{"canViewLearnPage":true,"insights":false,"manage":false},"administrator":{"canAddAudienceManagers":false}}}',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/managers`,
method: 'POST',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => JSON.stringify(parseThriveArray(params.managers, 'managers')),
},
transformResponse: async (response: Response): Promise<ThriveAddUsersResponse> => {
const data = await parseThriveResponse(response, 'Failed to add audience managers')
return {
success: true,
output: { result: { success: data?.success ?? null, failure: data?.failure } },
}
},
outputs: {
result: {
type: 'object',
description:
'The add/replace result, with successfully and unsuccessfully processed entities',
properties: THRIVE_ADD_USERS_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,76 @@
import type { ThriveAddUsersResponse, ThriveAudienceUsersParams } from '@/tools/thrive/types'
import { THRIVE_ADD_USERS_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const addAudienceMembersTool: ToolConfig<ThriveAudienceUsersParams, ThriveAddUsersResponse> =
{
id: 'thrive_add_audience_members',
name: 'Thrive Add Audience Members',
description: 'Add members to a Thrive audience by email, ref, or id.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
users: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'JSON array of user emails/refs/ids to add (1-100). Example: ["user@example.com"]',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/members`,
method: 'POST',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => JSON.stringify(parseThriveArray<string>(params.users, 'users')),
},
transformResponse: async (response: Response): Promise<ThriveAddUsersResponse> => {
const data = await parseThriveResponse(response, 'Failed to add audience members')
return {
success: true,
output: { result: { success: data?.success ?? null, failure: data?.failure } },
}
},
outputs: {
result: {
type: 'object',
description:
'The add/replace result, with successfully and unsuccessfully processed entities',
properties: THRIVE_ADD_USERS_OUTPUT_PROPERTIES,
},
},
}
+69
View File
@@ -0,0 +1,69 @@
import type { ThriveAddUserTagsParams, ThriveMessageResponse } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const addUserTagsTool: ToolConfig<ThriveAddUserTagsParams, ThriveMessageResponse> = {
id: 'thrive_add_user_tags',
name: 'Thrive Add User Tags',
description: 'Add one or more tags to a learner in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The learner ID',
},
tags: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'JSON array of tag names to add (1-100). Example: ["leadership"]',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/users/${encodeURIComponent(params.userId)}/tags`,
method: 'POST',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => ({ tags: parseThriveArray<string>(params.tags, 'tags') }),
},
transformResponse: async (response: Response): Promise<ThriveMessageResponse> => {
const data = await parseThriveResponse(response, 'Failed to add tags to learner')
return {
success: true,
output: { status: data?.status ?? null, message: data?.message ?? null },
}
},
outputs: {
status: { type: 'number', description: 'The HTTP status code of the operation' },
message: { type: 'string', description: 'A human-readable result message' },
},
}
+113
View File
@@ -0,0 +1,113 @@
import type { ThriveAssignmentResponse, ThriveCreateAssignmentParams } from '@/tools/thrive/types'
import { THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const createAssignmentTool: ToolConfig<
ThriveCreateAssignmentParams,
ThriveAssignmentResponse
> = {
id: 'thrive_create_assignment',
name: 'Thrive Create Assignment',
description: 'Create a compliance assignment in Thrive for an audience and content item.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience ID',
},
contentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The content ID for the primary content',
},
alternativeContentIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON array of content IDs that can also complete the assignment',
},
hideAlternativeContent: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to hide the alternative content',
},
completionPeriod: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The number of days required to complete the assignment (default 30)',
},
recurrence: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The number of days until the assignment will reoccur',
},
},
request: {
url: (params) => `${getThriveBaseUrl(params.host, 'v1')}/assignments`,
method: 'POST',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => {
const body: Record<string, any> = {
audienceId: params.audienceId,
contentId: params.contentId,
}
if (params.alternativeContentIds) {
body.alternativeContentIds = parseThriveArray<string>(
params.alternativeContentIds,
'alternativeContentIds'
)
}
if (params.hideAlternativeContent !== undefined) {
body.hideAlternativeContent = params.hideAlternativeContent
}
if (params.completionPeriod !== undefined) body.completionPeriod = params.completionPeriod
if (params.recurrence !== undefined) body.recurrence = params.recurrence
return body
},
},
transformResponse: async (response: Response): Promise<ThriveAssignmentResponse> => {
const data = await parseThriveResponse(response, 'Failed to create assignment')
return { success: true, output: { assignment: data ?? null } }
},
outputs: {
assignment: {
type: 'object',
description: 'The created assignment',
properties: THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES,
},
},
}
+84
View File
@@ -0,0 +1,84 @@
import type { ThriveAudienceResponse, ThriveCreateAudienceParams } from '@/tools/thrive/types'
import { THRIVE_AUDIENCE_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const createAudienceTool: ToolConfig<ThriveCreateAudienceParams, ThriveAudienceResponse> = {
id: 'thrive_create_audience',
name: 'Thrive Create Audience',
description: 'Create a new audience or structure in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The name of the audience (max 100 characters)',
},
reference: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The external reference for the audience (max 100 characters)',
},
parentId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'The id or reference of the parent audience/structure; leave blank for a parent audience/structure',
},
category: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "The audience category: 'audience' or 'structure'",
},
},
request: {
url: (params) => `${getThriveBaseUrl(params.host, 'v1')}/audiences`,
method: 'POST',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => {
const body: Record<string, any> = {}
if (params.name) body.name = params.name
if (params.reference) body.reference = params.reference
if (params.parentId) body.parentId = params.parentId
if (params.category) body.category = params.category
return body
},
},
transformResponse: async (response: Response): Promise<ThriveAudienceResponse> => {
const data = await parseThriveResponse(response, 'Failed to create audience')
return { success: true, output: { audience: data ?? null } }
},
outputs: {
audience: {
type: 'object',
description: 'The created audience',
properties: THRIVE_AUDIENCE_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,75 @@
import type {
ThriveCreateCompletionParams,
ThriveCreateCompletionResponse,
} from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const createCompletionTool: ToolConfig<
ThriveCreateCompletionParams,
ThriveCreateCompletionResponse
> = {
id: 'thrive_create_completion',
name: 'Thrive Create Completion',
description: 'Record a learning completion in Thrive for a user and content item.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user ID',
},
contentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The content ID for the content completed',
},
completedAt: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ISO8601 timestamp when the completion occurred',
},
},
request: {
url: (params) => `${getThriveBaseUrl(params.host, 'v1')}/learning/completions`,
method: 'POST',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => ({
userId: params.userId,
contentId: params.contentId,
completedAt: params.completedAt,
}),
},
transformResponse: async (response: Response): Promise<ThriveCreateCompletionResponse> => {
const data = await parseThriveResponse(response, 'Failed to create completion')
return { success: true, output: { statementId: data?.statementId ?? null } }
},
outputs: {
statementId: { type: 'string', description: 'The completion statement ID' },
},
}
+169
View File
@@ -0,0 +1,169 @@
import type { ThriveCreateUserParams, ThriveUserResponse } from '@/tools/thrive/types'
import { THRIVE_USER_LIFECYCLE_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveJsonObject,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const createUserTool: ToolConfig<ThriveCreateUserParams, ThriveUserResponse> = {
id: 'thrive_create_user',
name: 'Thrive Create User',
description: 'Create a new user in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
ref: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: "Your organisation's unique identifier for this individual",
},
firstName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The given name of the individual',
},
lastName: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The family name of the individual',
},
email: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "The email address for the user (required unless loginMethod is 'ref')",
},
loginMethod: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "How the user logs in: 'email' or 'ref' (defaults to 'email')",
},
role: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
"Role assigned: 'administrator', 'learneradmin', or 'learner' (defaults to 'learner')",
},
jobTitle: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "Name of this individual's role in your organisation",
},
managerRef: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "Your organisation's unique identifier for this individual's line manager",
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date this individual started with your organisation (ISO 8601)',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date this individual left your organisation (ISO 8601)',
},
timeZone: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "The user's preferred timezone (tenant default if omitted)",
},
languageCode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "The user's preferred language (e.g. 'en-gb')",
},
sso: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the account is managed by an authentication provider',
},
domain: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Domain this individual is associated with',
},
additionalFields: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON object of custom field key-value pairs. Example: {"department":"Sales"}',
},
},
request: {
url: (params) => `${getThriveBaseUrl(params.host, 'v2')}/users`,
method: 'POST',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => {
const body: Record<string, any> = {
ref: params.ref,
firstName: params.firstName,
lastName: params.lastName,
}
if (params.email) body.email = params.email
if (params.loginMethod) body.loginMethod = params.loginMethod
if (params.role) body.role = params.role
if (params.jobTitle) body.jobTitle = params.jobTitle
if (params.managerRef) body.managerRef = params.managerRef
if (params.startDate) body.startDate = params.startDate
if (params.endDate) body.endDate = params.endDate
if (params.timeZone) body.timeZone = params.timeZone
if (params.languageCode) body.languageCode = params.languageCode
if (params.sso !== undefined) body.sso = params.sso
if (params.domain) body.domain = params.domain
if (params.additionalFields) {
body.additionalFields = parseThriveJsonObject(params.additionalFields, 'additionalFields')
}
return body
},
},
transformResponse: async (response: Response): Promise<ThriveUserResponse> => {
const data = await parseThriveResponse(response, 'Failed to create user')
return { success: true, output: { user: data ?? null } }
},
outputs: {
user: {
type: 'object',
description: 'The created user',
properties: THRIVE_USER_LIFECYCLE_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,61 @@
import type { ThriveDeleteAssignmentParams, ThriveDeleteResponse } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteAssignmentTool: ToolConfig<ThriveDeleteAssignmentParams, ThriveDeleteResponse> =
{
id: 'thrive_delete_assignment',
name: 'Thrive Delete Assignment',
description: 'Delete a compliance assignment in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
assignmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The assignment ID',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/assignments/${encodeURIComponent(params.assignmentId)}`,
method: 'DELETE',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => ({ audienceId: params.audienceId }),
},
transformResponse: async (response: Response): Promise<ThriveDeleteResponse> => {
const data = await parseThriveResponse(response, 'Failed to delete assignment')
return { success: true, output: { success: data?.success ?? true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the assignment was deleted' },
},
}
+53
View File
@@ -0,0 +1,53 @@
import type { ThriveDeleteAudienceParams, ThriveDeleteResponse } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteAudienceTool: ToolConfig<ThriveDeleteAudienceParams, ThriveDeleteResponse> = {
id: 'thrive_delete_audience',
name: 'Thrive Delete Audience',
description: 'Delete an audience in Thrive (only if it has no child audiences).',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}`,
method: 'DELETE',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveDeleteResponse> => {
const data = await parseThriveResponse(response, 'Failed to delete audience')
return { success: true, output: { success: data?.success ?? true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the audience was deleted' },
},
}
+54
View File
@@ -0,0 +1,54 @@
import type { ThriveDeleteResponse, ThriveDeleteUserParams } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const deleteUserTool: ToolConfig<ThriveDeleteUserParams, ThriveDeleteResponse> = {
id: 'thrive_delete_user',
name: 'Thrive Delete User',
description:
'Permanently delete (obfuscate) a user in Thrive by ref while retaining training history.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
ref: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user ref to delete',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v2')}/users/ref/${encodeURIComponent(params.ref)}`,
method: 'DELETE',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveDeleteResponse> => {
const data = await parseThriveResponse(response, 'Failed to delete user')
return { success: true, output: { success: data?.success ?? true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the user was deleted' },
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveActivityResponse, ThriveGetActivityParams } from '@/tools/thrive/types'
import { THRIVE_ACTIVITY_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getActivityTool: ToolConfig<ThriveGetActivityParams, ThriveActivityResponse> = {
id: 'thrive_get_activity',
name: 'Thrive Get Activity',
description: 'Get a single activity record in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier of the activity',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/activity/${encodeURIComponent(params.id)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveActivityResponse> => {
const data = await parseThriveResponse(response, 'Failed to get activity')
return { success: true, output: { activity: data ?? null } }
},
outputs: {
activity: {
type: 'object',
description: 'The activity record',
properties: THRIVE_ACTIVITY_OUTPUT_PROPERTIES,
},
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveAssignmentResponse, ThriveGetAssignmentParams } from '@/tools/thrive/types'
import { THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getAssignmentTool: ToolConfig<ThriveGetAssignmentParams, ThriveAssignmentResponse> = {
id: 'thrive_get_assignment',
name: 'Thrive Get Assignment',
description: 'Get a single compliance assignment in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
assignmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The assignment ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/assignments/${encodeURIComponent(params.assignmentId)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveAssignmentResponse> => {
const data = await parseThriveResponse(response, 'Failed to get assignment')
return { success: true, output: { assignment: data ?? null } }
},
outputs: {
assignment: {
type: 'object',
description: 'The assignment',
properties: THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES,
},
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveAudienceResponse, ThriveGetAudienceParams } from '@/tools/thrive/types'
import { THRIVE_AUDIENCE_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getAudienceTool: ToolConfig<ThriveGetAudienceParams, ThriveAudienceResponse> = {
id: 'thrive_get_audience',
name: 'Thrive Get Audience',
description: 'Get a single audience or structure in Thrive by id or reference.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveAudienceResponse> => {
const data = await parseThriveResponse(response, 'Failed to get audience')
return { success: true, output: { audience: data ?? null } }
},
outputs: {
audience: {
type: 'object',
description: 'The audience',
properties: THRIVE_AUDIENCE_OUTPUT_PROPERTIES,
},
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveCompletionResponse, ThriveGetCompletionParams } from '@/tools/thrive/types'
import { THRIVE_COMPLETION_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getCompletionTool: ToolConfig<ThriveGetCompletionParams, ThriveCompletionResponse> = {
id: 'thrive_get_completion',
name: 'Thrive Get Completion',
description: 'Get a single learning completion record in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The completion ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/learning/completions/${encodeURIComponent(params.id)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCompletionResponse> => {
const data = await parseThriveResponse(response, 'Failed to get completion')
return { success: true, output: { completion: data ?? null } }
},
outputs: {
completion: {
type: 'object',
description: 'The completion record',
properties: THRIVE_COMPLETION_OUTPUT_PROPERTIES,
},
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveContentResponse, ThriveGetContentParams } from '@/tools/thrive/types'
import { THRIVE_CONTENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getContentTool: ToolConfig<ThriveGetContentParams, ThriveContentResponse> = {
id: 'thrive_get_content',
name: 'Thrive Get Content',
description: 'Get a single content record in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier of the content item',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/contents/${encodeURIComponent(params.id)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveContentResponse> => {
const data = await parseThriveResponse(response, 'Failed to get content')
return { success: true, output: { content: data ?? null } }
},
outputs: {
content: {
type: 'object',
description: 'The content record',
properties: THRIVE_CONTENT_OUTPUT_PROPERTIES,
},
},
}
+59
View File
@@ -0,0 +1,59 @@
import type { ThriveCpdCategoryResponse, ThriveGetCpdCategoryParams } from '@/tools/thrive/types'
import { THRIVE_CPD_CATEGORY_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getCpdCategoryTool: ToolConfig<ThriveGetCpdCategoryParams, ThriveCpdCategoryResponse> =
{
id: 'thrive_get_cpd_category',
name: 'Thrive Get CPD Category',
description: 'Get a single CPD category in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
categoryId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The CPD category ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/cpdCategories/${encodeURIComponent(params.categoryId)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCpdCategoryResponse> => {
const data = await parseThriveResponse(response, 'Failed to get CPD category')
return { success: true, output: { category: data ?? null } }
},
outputs: {
category: {
type: 'object',
description: 'The CPD category',
properties: THRIVE_CPD_CATEGORY_OUTPUT_PROPERTIES,
},
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveCpdEntryResponse, ThriveGetCpdEntryParams } from '@/tools/thrive/types'
import { THRIVE_CPD_ENTRY_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getCpdEntryTool: ToolConfig<ThriveGetCpdEntryParams, ThriveCpdEntryResponse> = {
id: 'thrive_get_cpd_entry',
name: 'Thrive Get CPD Entry',
description: 'Get a single CPD log entry in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
logEntryId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The CPD log entry ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/cpdEntries/${encodeURIComponent(params.logEntryId)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCpdEntryResponse> => {
const data = await parseThriveResponse(response, 'Failed to get CPD entry')
return { success: true, output: { entry: data ?? null } }
},
outputs: {
entry: {
type: 'object',
description: 'The CPD entry',
properties: THRIVE_CPD_ENTRY_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,64 @@
import type {
ThriveCpdRequirementResponse,
ThriveGetCpdRequirementParams,
} from '@/tools/thrive/types'
import { THRIVE_CPD_REQUIREMENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getCpdRequirementTool: ToolConfig<
ThriveGetCpdRequirementParams,
ThriveCpdRequirementResponse
> = {
id: 'thrive_get_cpd_requirement',
name: 'Thrive Get CPD Requirement',
description: 'Get a single CPD requirement summary in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceRequirementId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The CPD requirement ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/cpdRequirementSummaries/${encodeURIComponent(params.audienceRequirementId)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCpdRequirementResponse> => {
const data = await parseThriveResponse(response, 'Failed to get CPD requirement')
return { success: true, output: { requirement: data ?? null } }
},
outputs: {
requirement: {
type: 'object',
description: 'The CPD requirement',
properties: THRIVE_CPD_REQUIREMENT_OUTPUT_PROPERTIES,
},
},
}
+64
View File
@@ -0,0 +1,64 @@
import type { ThriveEnrolmentResponse, ThriveGetEnrolmentParams } from '@/tools/thrive/types'
import { THRIVE_ENROLMENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getEnrolmentTool: ToolConfig<ThriveGetEnrolmentParams, ThriveEnrolmentResponse> = {
id: 'thrive_get_enrolment',
name: 'Thrive Get Enrolment',
description: 'Get a single enrolment for a compliance assignment in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
assignmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The assignment ID',
},
enrolmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The enrolment ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/assignments/${encodeURIComponent(params.assignmentId)}/enrolments/${encodeURIComponent(params.enrolmentId)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveEnrolmentResponse> => {
const data = await parseThriveResponse(response, 'Failed to get enrolment')
return { success: true, output: { enrolment: data ?? null } }
},
outputs: {
enrolment: {
type: 'object',
description: 'The enrolment',
properties: THRIVE_ENROLMENT_OUTPUT_PROPERTIES,
},
},
}
+52
View File
@@ -0,0 +1,52 @@
import type { ThriveGetSkillLevelsParams, ThriveSkillLevelsResponse } from '@/tools/thrive/types'
import { THRIVE_SKILL_LEVEL_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getSkillLevelsTool: ToolConfig<ThriveGetSkillLevelsParams, ThriveSkillLevelsResponse> =
{
id: 'thrive_get_skill_levels',
name: 'Thrive Get Skill Levels',
description: 'Get the available skill levels configured in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
},
request: {
url: (params) => `${getThriveBaseUrl(params.host, 'v1')}/skills/levels`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveSkillLevelsResponse> => {
const data = await parseThriveResponse(response, 'Failed to get skill levels')
return { success: true, output: { levels: Array.isArray(data) ? data : [] } }
},
outputs: {
levels: {
type: 'array',
description: 'The available skill levels',
items: { type: 'object', properties: THRIVE_SKILL_LEVEL_OUTPUT_PROPERTIES },
},
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveGetTagParams, ThriveTagResponse } from '@/tools/thrive/types'
import { THRIVE_TAG_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getTagTool: ToolConfig<ThriveGetTagParams, ThriveTagResponse> = {
id: 'thrive_get_tag',
name: 'Thrive Get Tag',
description: 'Get a single tag in Thrive by its ID.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
tagId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The tag ID',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/tags/${encodeURIComponent(params.tagId)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveTagResponse> => {
const data = await parseThriveResponse(response, 'Failed to get tag')
return { success: true, output: { tag: data ?? null } }
},
outputs: {
tag: {
type: 'object',
description: 'The tag',
properties: THRIVE_TAG_OUTPUT_PROPERTIES,
},
},
}
+57
View File
@@ -0,0 +1,57 @@
import type { ThriveGetUserByIdParams, ThriveUserResponse } from '@/tools/thrive/types'
import { THRIVE_USER_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getUserByIdTool: ToolConfig<ThriveGetUserByIdParams, ThriveUserResponse> = {
id: 'thrive_get_user_by_id',
name: 'Thrive Get User by ID',
description: 'Get a single user in Thrive by their ID and return basic user information.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user ID',
},
},
request: {
url: (params) => `${getThriveBaseUrl(params.host, 'v1')}/user/${encodeURIComponent(params.id)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveUserResponse> => {
const data = await parseThriveResponse(response, 'Failed to get user')
return { success: true, output: { user: data ?? null } }
},
outputs: {
user: {
type: 'object',
description: 'The user',
properties: THRIVE_USER_OUTPUT_PROPERTIES,
},
},
}
+58
View File
@@ -0,0 +1,58 @@
import type { ThriveGetUserByRefParams, ThriveUserResponse } from '@/tools/thrive/types'
import { THRIVE_BASIC_USER_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const getUserByRefTool: ToolConfig<ThriveGetUserByRefParams, ThriveUserResponse> = {
id: 'thrive_get_user_by_ref',
name: 'Thrive Get User by Ref',
description: 'Get a single user in Thrive by their ref and return basic user information.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
ref: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user ref',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/users/ref/${encodeURIComponent(params.ref)}`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveUserResponse> => {
const data = await parseThriveResponse(response, 'Failed to get user')
return { success: true, output: { user: data ?? null } }
},
outputs: {
user: {
type: 'object',
description: 'The user (basic information)',
properties: THRIVE_BASIC_USER_OUTPUT_PROPERTIES,
},
},
}
+102
View File
@@ -0,0 +1,102 @@
import { addAudienceManagersTool } from '@/tools/thrive/add_audience_managers'
import { addAudienceMembersTool } from '@/tools/thrive/add_audience_members'
import { addUserTagsTool } from '@/tools/thrive/add_user_tags'
import { createAssignmentTool } from '@/tools/thrive/create_assignment'
import { createAudienceTool } from '@/tools/thrive/create_audience'
import { createCompletionTool } from '@/tools/thrive/create_completion'
import { createUserTool } from '@/tools/thrive/create_user'
import { deleteAssignmentTool } from '@/tools/thrive/delete_assignment'
import { deleteAudienceTool } from '@/tools/thrive/delete_audience'
import { deleteUserTool } from '@/tools/thrive/delete_user'
import { getActivityTool } from '@/tools/thrive/get_activity'
import { getAssignmentTool } from '@/tools/thrive/get_assignment'
import { getAudienceTool } from '@/tools/thrive/get_audience'
import { getCompletionTool } from '@/tools/thrive/get_completion'
import { getContentTool } from '@/tools/thrive/get_content'
import { getCpdCategoryTool } from '@/tools/thrive/get_cpd_category'
import { getCpdEntryTool } from '@/tools/thrive/get_cpd_entry'
import { getCpdRequirementTool } from '@/tools/thrive/get_cpd_requirement'
import { getEnrolmentTool } from '@/tools/thrive/get_enrolment'
import { getSkillLevelsTool } from '@/tools/thrive/get_skill_levels'
import { getTagTool } from '@/tools/thrive/get_tag'
import { getUserByIdTool } from '@/tools/thrive/get_user_by_id'
import { getUserByRefTool } from '@/tools/thrive/get_user_by_ref'
import { listAssignmentsTool } from '@/tools/thrive/list_assignments'
import { listAudienceManagersTool } from '@/tools/thrive/list_audience_managers'
import { listAudienceMembersTool } from '@/tools/thrive/list_audience_members'
import { listAudiencesTool } from '@/tools/thrive/list_audiences'
import { listCompletionsTool } from '@/tools/thrive/list_completions'
import { listEnrolmentsTool } from '@/tools/thrive/list_enrolments'
import { listTagsTool } from '@/tools/thrive/list_tags'
import { queryActivitiesTool } from '@/tools/thrive/query_activities'
import { queryContentTool } from '@/tools/thrive/query_content'
import { queryCpdCategoriesTool } from '@/tools/thrive/query_cpd_categories'
import { queryCpdEntriesTool } from '@/tools/thrive/query_cpd_entries'
import { queryCpdRequirementsTool } from '@/tools/thrive/query_cpd_requirements'
import { queryCpdUserSummariesTool } from '@/tools/thrive/query_cpd_user_summaries'
import { removeAudienceManagerTool } from '@/tools/thrive/remove_audience_manager'
import { removeAudienceMemberTool } from '@/tools/thrive/remove_audience_member'
import { removeUserTagsTool } from '@/tools/thrive/remove_user_tags'
import { replaceAudienceManagersTool } from '@/tools/thrive/replace_audience_managers'
import { replaceAudienceMembersTool } from '@/tools/thrive/replace_audience_members'
import { searchUsersTool } from '@/tools/thrive/search_users'
import { suspendUserTool } from '@/tools/thrive/suspend_user'
import { updateAssignmentTool } from '@/tools/thrive/update_assignment'
import { updateAudienceTool } from '@/tools/thrive/update_audience'
import { updateUserTool } from '@/tools/thrive/update_user'
import { updateUserSkillsTool } from '@/tools/thrive/update_user_skills'
export const thriveCreateUserTool = createUserTool
export const thriveUpdateUserTool = updateUserTool
export const thriveDeleteUserTool = deleteUserTool
export const thriveSuspendUserTool = suspendUserTool
export const thriveSearchUsersTool = searchUsersTool
export const thriveGetUserByIdTool = getUserByIdTool
export const thriveGetUserByRefTool = getUserByRefTool
export const thriveListAudiencesTool = listAudiencesTool
export const thriveCreateAudienceTool = createAudienceTool
export const thriveGetAudienceTool = getAudienceTool
export const thriveUpdateAudienceTool = updateAudienceTool
export const thriveDeleteAudienceTool = deleteAudienceTool
export const thriveListAudienceMembersTool = listAudienceMembersTool
export const thriveAddAudienceMembersTool = addAudienceMembersTool
export const thriveReplaceAudienceMembersTool = replaceAudienceMembersTool
export const thriveRemoveAudienceMemberTool = removeAudienceMemberTool
export const thriveListAudienceManagersTool = listAudienceManagersTool
export const thriveAddAudienceManagersTool = addAudienceManagersTool
export const thriveReplaceAudienceManagersTool = replaceAudienceManagersTool
export const thriveRemoveAudienceManagerTool = removeAudienceManagerTool
export const thriveListAssignmentsTool = listAssignmentsTool
export const thriveCreateAssignmentTool = createAssignmentTool
export const thriveGetAssignmentTool = getAssignmentTool
export const thriveUpdateAssignmentTool = updateAssignmentTool
export const thriveDeleteAssignmentTool = deleteAssignmentTool
export const thriveListEnrolmentsTool = listEnrolmentsTool
export const thriveGetEnrolmentTool = getEnrolmentTool
export const thriveListCompletionsTool = listCompletionsTool
export const thriveGetCompletionTool = getCompletionTool
export const thriveCreateCompletionTool = createCompletionTool
export const thriveGetContentTool = getContentTool
export const thriveQueryContentTool = queryContentTool
export const thriveGetActivityTool = getActivityTool
export const thriveQueryActivitiesTool = queryActivitiesTool
export const thriveGetCpdCategoryTool = getCpdCategoryTool
export const thriveQueryCpdCategoriesTool = queryCpdCategoriesTool
export const thriveGetCpdEntryTool = getCpdEntryTool
export const thriveQueryCpdEntriesTool = queryCpdEntriesTool
export const thriveGetCpdRequirementTool = getCpdRequirementTool
export const thriveQueryCpdRequirementsTool = queryCpdRequirementsTool
export const thriveQueryCpdUserSummariesTool = queryCpdUserSummariesTool
export const thriveListTagsTool = listTagsTool
export const thriveGetTagTool = getTagTool
export const thriveAddUserTagsTool = addUserTagsTool
export const thriveRemoveUserTagsTool = removeUserTagsTool
export const thriveUpdateUserSkillsTool = updateUserSkillsTool
export const thriveGetSkillLevelsTool = getSkillLevelsTool
+93
View File
@@ -0,0 +1,93 @@
import type {
ThriveListAssignmentsParams,
ThriveListAssignmentsResponse,
} from '@/tools/thrive/types'
import { THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const listAssignmentsTool: ToolConfig<
ThriveListAssignmentsParams,
ThriveListAssignmentsResponse
> = {
id: 'thrive_list_assignments',
name: 'Thrive List Assignments',
description: 'List compliance assignments in Thrive, optionally filtered by audience.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by audience ID or audience reference',
},
updatedSince: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Return only items updated on or after this date/time (ISO 8601)',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-100, default 100)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/assignments`)
appendThriveQuery(url, 'audienceId', params.audienceId)
appendThriveQuery(url, 'updatedSince', params.updatedSince)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveListAssignmentsResponse> => {
const data = await parseThriveResponse(response, 'Failed to list assignments')
return { success: true, output: { assignments: Array.isArray(data) ? data : [] } }
},
outputs: {
assignments: {
type: 'array',
description: 'The matching assignments',
items: { type: 'object', properties: THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES },
},
},
}
@@ -0,0 +1,64 @@
import type {
ThriveListAudienceManagersParams,
ThriveListAudienceManagersResponse,
} from '@/tools/thrive/types'
import { THRIVE_AUDIENCE_MANAGER_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const listAudienceManagersTool: ToolConfig<
ThriveListAudienceManagersParams,
ThriveListAudienceManagersResponse
> = {
id: 'thrive_list_audience_managers',
name: 'Thrive List Audience Managers',
description: 'List the managers of a Thrive audience.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/managers`,
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveListAudienceManagersResponse> => {
const data = await parseThriveResponse(response, 'Failed to list audience managers')
return { success: true, output: { managers: Array.isArray(data) ? data : [] } }
},
outputs: {
managers: {
type: 'array',
description: 'The audience managers',
items: { type: 'object', properties: THRIVE_AUDIENCE_MANAGER_OUTPUT_PROPERTIES },
},
},
}
@@ -0,0 +1,98 @@
import type {
ThriveListAudienceMembersParams,
ThriveListAudienceMembersResponse,
} from '@/tools/thrive/types'
import {
THRIVE_AUDIENCE_MEMBER_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const listAudienceMembersTool: ToolConfig<
ThriveListAudienceMembersParams,
ThriveListAudienceMembersResponse
> = {
id: 'thrive_list_audience_members',
name: 'Thrive List Audience Members',
description: 'List the members of a Thrive audience with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
},
request: {
url: (params) => {
const url = new URL(
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/members`
)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveListAudienceMembersResponse> => {
const data = await parseThriveResponse(response, 'Failed to list audience members')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The audience members',
items: { type: 'object', properties: THRIVE_AUDIENCE_MEMBER_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
+99
View File
@@ -0,0 +1,99 @@
import type { ThriveListAudiencesParams, ThriveListAudiencesResponse } from '@/tools/thrive/types'
import {
THRIVE_AUDIENCE_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const listAudiencesTool: ToolConfig<ThriveListAudiencesParams, ThriveListAudiencesResponse> =
{
id: 'thrive_list_audiences',
name: 'Thrive List Audiences',
description: 'List audiences and structures in Thrive with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
apiControlled: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter to only return audiences which are / are not API controlled',
},
updatedSince: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Return only audiences updated on or after this date/time (ISO 8601)',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/audiences`)
appendThriveQuery(url, 'apiControlled', params.apiControlled)
appendThriveQuery(url, 'updatedSince', params.updatedSince)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveListAudiencesResponse> => {
const data = await parseThriveResponse(response, 'Failed to list audiences')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching audiences',
items: { type: 'object', properties: THRIVE_AUDIENCE_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
+115
View File
@@ -0,0 +1,115 @@
import type {
ThriveListCompletionsParams,
ThriveListCompletionsResponse,
} from '@/tools/thrive/types'
import { THRIVE_COMPLETION_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const listCompletionsTool: ToolConfig<
ThriveListCompletionsParams,
ThriveListCompletionsResponse
> = {
id: 'thrive_list_completions',
name: 'Thrive List Completions',
description:
'List learning completion records in Thrive, optionally filtered by user or content.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
contentId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by content',
},
isRPL: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter by completions imported via Recognition of Prior Learning (RPL)',
},
userId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by user',
},
completedDateRangeStart: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by completedDate (completedDate >= this date/date-time)',
},
completedDateRangeEnd: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by completedDate (completedDate <= this date/date-time)',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 1000)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/learning/completions`)
appendThriveQuery(url, 'contentId', params.contentId)
appendThriveQuery(url, 'isRPL', params.isRPL)
appendThriveQuery(url, 'userId', params.userId)
appendThriveQuery(url, 'completedDateRangeStart', params.completedDateRangeStart)
appendThriveQuery(url, 'completedDateRangeEnd', params.completedDateRangeEnd)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveListCompletionsResponse> => {
const data = await parseThriveResponse(response, 'Failed to list completions')
return { success: true, output: { completions: Array.isArray(data) ? data : [] } }
},
outputs: {
completions: {
type: 'array',
description: 'The matching completion records',
items: { type: 'object', properties: THRIVE_COMPLETION_OUTPUT_PROPERTIES },
},
},
}
+106
View File
@@ -0,0 +1,106 @@
import type { ThriveListEnrolmentsParams, ThriveListEnrolmentsResponse } from '@/tools/thrive/types'
import { THRIVE_ENROLMENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const listEnrolmentsTool: ToolConfig<
ThriveListEnrolmentsParams,
ThriveListEnrolmentsResponse
> = {
id: 'thrive_list_enrolments',
name: 'Thrive List Enrolments',
description: 'List enrolments for a compliance assignment in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
assignmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The assignment ID',
},
updatedAtFrom: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start date to filter enrolments from (ISO 8601)',
},
updatedAtTo: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date to filter enrolments up to (ISO 8601). Requires updatedAtFrom.',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Filter by enrolment status: archived, complete, open, overdue, scheduled, or unassigned',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-100, default 100)',
},
},
request: {
url: (params) => {
const url = new URL(
`${getThriveBaseUrl(params.host, 'v1')}/assignments/${encodeURIComponent(params.assignmentId)}/enrolments`
)
appendThriveQuery(url, 'updatedAtFrom', params.updatedAtFrom)
appendThriveQuery(url, 'updatedAtTo', params.updatedAtTo)
appendThriveQuery(url, 'status', params.status)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveListEnrolmentsResponse> => {
const data = await parseThriveResponse(response, 'Failed to list enrolments')
return { success: true, output: { enrolments: Array.isArray(data) ? data : [] } }
},
outputs: {
enrolments: {
type: 'array',
description: 'The matching enrolments',
items: { type: 'object', properties: THRIVE_ENROLMENT_OUTPUT_PROPERTIES },
},
},
}
+91
View File
@@ -0,0 +1,91 @@
import type { ThriveListTagsParams, ThriveListTagsResponse } from '@/tools/thrive/types'
import {
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
THRIVE_TAG_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const listTagsTool: ToolConfig<ThriveListTagsParams, ThriveListTagsResponse> = {
id: 'thrive_list_tags',
name: 'Thrive List Tags',
description: 'List tags in Thrive and return tag information with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
updatedSince: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Return only tags updated on or after this date/time (ISO 8601)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/tags`)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
appendThriveQuery(url, 'updatedSince', params.updatedSince)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveListTagsResponse> => {
const data = await parseThriveResponse(response, 'Failed to list tags')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The tags',
items: { type: 'object', properties: THRIVE_TAG_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
+132
View File
@@ -0,0 +1,132 @@
import type {
ThriveQueryActivitiesParams,
ThriveQueryActivitiesResponse,
} from '@/tools/thrive/types'
import {
THRIVE_ACTIVITY_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const queryActivitiesTool: ToolConfig<
ThriveQueryActivitiesParams,
ThriveQueryActivitiesResponse
> = {
id: 'thrive_query_activities',
name: 'Thrive Query Activities',
description: 'Query activity records in Thrive with pagination and filtering options.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 20)',
},
actions: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'comma-separated activity types e.g. viewed,completed',
},
omitActions: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'comma-separated activity types e.g. viewed,completed',
},
contentIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'comma-separated content IDs',
},
contentType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by content type',
},
timestampFrom: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'format YYYY-MM-DD hh:mm:ss',
},
timestampTo: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'format YYYY-MM-DD hh:mm:ss',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/activities`)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
appendThriveQuery(url, 'actions', params.actions)
appendThriveQuery(url, 'omitActions', params.omitActions)
appendThriveQuery(url, 'contentIds', params.contentIds)
appendThriveQuery(url, 'contentType', params.contentType)
appendThriveQuery(url, 'timestampFrom', params.timestampFrom)
appendThriveQuery(url, 'timestampTo', params.timestampTo)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveQueryActivitiesResponse> => {
const data = await parseThriveResponse(response, 'Failed to query activities')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching activity records',
items: { type: 'object', properties: THRIVE_ACTIVITY_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
+107
View File
@@ -0,0 +1,107 @@
import type { ThriveQueryContentParams, ThriveQueryContentResponse } from '@/tools/thrive/types'
import {
THRIVE_CONTENT_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const queryContentTool: ToolConfig<ThriveQueryContentParams, ThriveQueryContentResponse> = {
id: 'thrive_query_content',
name: 'Thrive Query Content',
description: 'Query content records in Thrive with pagination and filtering options.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 20)',
},
types: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated content types (article, assessment, broadcast, cmi5, elearning, event, file, pathway, question, quiz, scorm, url, video, mixed). If both set, omitTypes is ignored.',
},
omitTypes: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated content types (article, assessment, broadcast, cmi5, elearning, event, file, pathway, question, quiz, scorm, url, video, mixed). If both set, omitTypes is ignored.',
},
updatedSince: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Return only items updated on or after this date/time (ISO 8601)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/contents`)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
appendThriveQuery(url, 'types', params.types)
appendThriveQuery(url, 'omitTypes', params.omitTypes)
appendThriveQuery(url, 'updatedSince', params.updatedSince)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveQueryContentResponse> => {
const data = await parseThriveResponse(response, 'Failed to query content')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching content records',
items: { type: 'object', properties: THRIVE_CONTENT_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,97 @@
import type {
ThriveCpdPaginatedResponse,
ThriveQueryCpdCategoriesParams,
} from '@/tools/thrive/types'
import {
THRIVE_CPD_CATEGORY_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const queryCpdCategoriesTool: ToolConfig<
ThriveQueryCpdCategoriesParams,
ThriveCpdPaginatedResponse
> = {
id: 'thrive_query_cpd_categories',
name: 'Thrive Query CPD Categories',
description: 'Query CPD categories in Thrive and return results with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
updatedSince: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Return only items updated on or after this date/time (ISO 8601)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/cpdCategories`)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
appendThriveQuery(url, 'updatedSince', params.updatedSince)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCpdPaginatedResponse> => {
const data = await parseThriveResponse(response, 'Failed to query CPD categories')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching CPD categories',
items: { type: 'object', properties: THRIVE_CPD_CATEGORY_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
+101
View File
@@ -0,0 +1,101 @@
import type { ThriveCpdPaginatedResponse, ThriveQueryCpdEntriesParams } from '@/tools/thrive/types'
import {
THRIVE_CPD_ENTRY_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const queryCpdEntriesTool: ToolConfig<
ThriveQueryCpdEntriesParams,
ThriveCpdPaginatedResponse
> = {
id: 'thrive_query_cpd_entries',
name: 'Thrive Query CPD Entries',
description: 'Query CPD log entries in Thrive and return results with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
entryDateFrom: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter entries after this date (format YYYY-MM-DD hh:mm:ss)',
},
entryDateTo: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter entries before this date (format YYYY-MM-DD hh:mm:ss)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/cpdEntries`)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
appendThriveQuery(url, 'entryDateFrom', params.entryDateFrom)
appendThriveQuery(url, 'entryDateTo', params.entryDateTo)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCpdPaginatedResponse> => {
const data = await parseThriveResponse(response, 'Failed to query CPD entries')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching CPD entries',
items: { type: 'object', properties: THRIVE_CPD_ENTRY_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,97 @@
import type {
ThriveCpdPaginatedResponse,
ThriveQueryCpdRequirementsParams,
} from '@/tools/thrive/types'
import {
THRIVE_CPD_REQUIREMENT_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const queryCpdRequirementsTool: ToolConfig<
ThriveQueryCpdRequirementsParams,
ThriveCpdPaginatedResponse
> = {
id: 'thrive_query_cpd_requirements',
name: 'Thrive Query CPD Requirements',
description: 'Query CPD requirement summaries in Thrive and return results with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
updatedSince: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Return only items updated on or after this date/time (ISO 8601)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/cpdRequirementSummaries`)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
appendThriveQuery(url, 'updatedSince', params.updatedSince)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCpdPaginatedResponse> => {
const data = await parseThriveResponse(response, 'Failed to query CPD requirements')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching CPD requirements',
items: { type: 'object', properties: THRIVE_CPD_REQUIREMENT_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,111 @@
import type {
ThriveCpdPaginatedResponse,
ThriveQueryCpdUserSummariesParams,
} from '@/tools/thrive/types'
import {
THRIVE_CPD_USER_SUMMARY_OUTPUT_PROPERTIES,
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const queryCpdUserSummariesTool: ToolConfig<
ThriveQueryCpdUserSummariesParams,
ThriveCpdPaginatedResponse
> = {
id: 'thrive_query_cpd_user_summaries',
name: 'Thrive Query CPD User Summaries',
description: 'Query CPD user log summaries in Thrive and return results with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
entryDateFrom: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Filter entries after this date (format YYYY-MM-DDThh:mm:ss)',
},
entryDateTo: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Filter entries before this date (format YYYY-MM-DDThh:mm:ss)',
},
userIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated user IDs to filter by',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/cpdUserLogSummaries`)
appendThriveQuery(url, 'entryDateFrom', params.entryDateFrom)
appendThriveQuery(url, 'entryDateTo', params.entryDateTo)
appendThriveQuery(url, 'userIds', params.userIds)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveCpdPaginatedResponse> => {
const data = await parseThriveResponse(response, 'Failed to query CPD user summaries')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching CPD user summaries',
items: { type: 'object', properties: THRIVE_CPD_USER_SUMMARY_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,62 @@
import type { ThriveDeleteResponse, ThriveRemoveAudienceManagerParams } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const removeAudienceManagerTool: ToolConfig<
ThriveRemoveAudienceManagerParams,
ThriveDeleteResponse
> = {
id: 'thrive_remove_audience_manager',
name: 'Thrive Remove Audience Manager',
description: 'Remove a single manager from a Thrive audience.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user email, ref, or id to remove as a manager',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/managers/${encodeURIComponent(params.userId)}`,
method: 'DELETE',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveDeleteResponse> => {
const data = await parseThriveResponse(response, 'Failed to remove audience manager')
return { success: true, output: { success: data?.success ?? true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the audience manager was removed' },
},
}
@@ -0,0 +1,62 @@
import type { ThriveDeleteResponse, ThriveRemoveAudienceMemberParams } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const removeAudienceMemberTool: ToolConfig<
ThriveRemoveAudienceMemberParams,
ThriveDeleteResponse
> = {
id: 'thrive_remove_audience_member',
name: 'Thrive Remove Audience Member',
description: 'Remove a single member from a Thrive audience.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
userRef: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user email, ref, or id to remove',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/members/${encodeURIComponent(params.userRef)}`,
method: 'DELETE',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveDeleteResponse> => {
const data = await parseThriveResponse(response, 'Failed to remove audience member')
return { success: true, output: { success: data?.success ?? true } }
},
outputs: {
success: { type: 'boolean', description: 'Whether the audience member was removed' },
},
}
+73
View File
@@ -0,0 +1,73 @@
import type { ThriveMessageResponse, ThriveRemoveUserTagsParams } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const removeUserTagsTool: ToolConfig<ThriveRemoveUserTagsParams, ThriveMessageResponse> = {
id: 'thrive_remove_user_tags',
name: 'Thrive Remove User Tags',
description: 'Remove one or more tags from a learner in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The learner ID',
},
tags: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'JSON array of tag names to remove (1-100). Example: ["leadership"]',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/users/${encodeURIComponent(params.userId)}/tags`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => ({
op: 'remove',
path: 'tags',
value: parseThriveArray<string>(params.tags, 'tags'),
}),
},
transformResponse: async (response: Response): Promise<ThriveMessageResponse> => {
const data = await parseThriveResponse(response, 'Failed to remove tags from learner')
return {
success: true,
output: { status: data?.status ?? null, message: data?.message ?? null },
}
},
outputs: {
status: { type: 'number', description: 'The HTTP status code of the operation' },
message: { type: 'string', description: 'A human-readable result message' },
},
}
@@ -0,0 +1,79 @@
import type { ThriveAddUsersResponse, ThriveAudienceManagersParams } from '@/tools/thrive/types'
import { THRIVE_ADD_USERS_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const replaceAudienceManagersTool: ToolConfig<
ThriveAudienceManagersParams,
ThriveAddUsersResponse
> = {
id: 'thrive_replace_audience_managers',
name: 'Thrive Replace Audience Managers',
description:
"Replace a Thrive audience's entire manager list with the given managers (does not support an empty array).",
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
managers: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'JSON array of manager objects that replaces the whole manager list (1-100, no empty array). Each: {"reference":"user@example.com","permissions":{"audienceManager":{"manageContent":true,"assignments":true},"peopleManager":{"canViewLearnPage":true,"insights":false,"manage":false},"administrator":{"canAddAudienceManagers":false}}}',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/managers`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => JSON.stringify(parseThriveArray(params.managers, 'managers')),
},
transformResponse: async (response: Response): Promise<ThriveAddUsersResponse> => {
const data = await parseThriveResponse(response, 'Failed to replace audience managers')
return {
success: true,
output: { result: { success: data?.success ?? null, failure: data?.failure } },
}
},
outputs: {
result: {
type: 'object',
description:
'The add/replace result, with successfully and unsuccessfully processed entities',
properties: THRIVE_ADD_USERS_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,79 @@
import type { ThriveAddUsersResponse, ThriveAudienceUsersParams } from '@/tools/thrive/types'
import { THRIVE_ADD_USERS_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const replaceAudienceMembersTool: ToolConfig<
ThriveAudienceUsersParams,
ThriveAddUsersResponse
> = {
id: 'thrive_replace_audience_members',
name: 'Thrive Replace Audience Members',
description:
"Replace a Thrive audience's entire members list with the given users (does not support an empty array).",
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
users: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'JSON array of user emails/refs/ids that replaces the whole members list (1-100, no empty array). Example: ["user@example.com"]',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}/members`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => JSON.stringify(parseThriveArray<string>(params.users, 'users')),
},
transformResponse: async (response: Response): Promise<ThriveAddUsersResponse> => {
const data = await parseThriveResponse(response, 'Failed to replace audience members')
return {
success: true,
output: { result: { success: data?.success ?? null, failure: data?.failure } },
}
},
outputs: {
result: {
type: 'object',
description:
'The add/replace result, with successfully and unsuccessfully processed entities',
properties: THRIVE_ADD_USERS_OUTPUT_PROPERTIES,
},
},
}
+112
View File
@@ -0,0 +1,112 @@
import type { ThriveSearchUsersParams, ThriveSearchUsersResponse } from '@/tools/thrive/types'
import {
THRIVE_PAGINATION_OUTPUT_PROPERTIES,
THRIVE_USER_OUTPUT_PROPERTIES,
} from '@/tools/thrive/types'
import {
appendThriveQuery,
getThriveBaseUrl,
getThriveHeaders,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const searchUsersTool: ToolConfig<ThriveSearchUsersParams, ThriveSearchUsersResponse> = {
id: 'thrive_search_users',
name: 'Thrive Search Users',
description: 'Search users in Thrive and return basic user information with pagination.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (default 1)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (1-1000, default 100)',
},
updatedSince: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Return only users updated on or after this date/time (ISO 8601)',
},
statuses: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated statuses to include: active, inactive, expired, new',
},
omitStatuses: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated statuses to exclude: active, inactive, expired, new',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by a single status: active, inactive, expired, or new',
},
},
request: {
url: (params) => {
const url = new URL(`${getThriveBaseUrl(params.host, 'v1')}/users`)
appendThriveQuery(url, 'page', params.page)
appendThriveQuery(url, 'perPage', params.perPage)
appendThriveQuery(url, 'updatedSince', params.updatedSince)
appendThriveQuery(url, 'statuses', params.statuses)
appendThriveQuery(url, 'omitStatuses', params.omitStatuses)
appendThriveQuery(url, 'status', params.status)
return url.toString()
},
method: 'GET',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
},
transformResponse: async (response: Response): Promise<ThriveSearchUsersResponse> => {
const data = await parseThriveResponse(response, 'Failed to search users')
return {
success: true,
output: { results: data?.results ?? [], pagination: data?.pagination ?? null },
}
},
outputs: {
results: {
type: 'array',
description: 'The matching users',
items: { type: 'object', properties: THRIVE_USER_OUTPUT_PROPERTIES },
},
pagination: {
type: 'object',
description: 'Pagination details',
properties: THRIVE_PAGINATION_OUTPUT_PROPERTIES,
},
},
}
+69
View File
@@ -0,0 +1,69 @@
import type { ThriveSuspendUserParams, ThriveUserResponse } from '@/tools/thrive/types'
import { THRIVE_USER_LIFECYCLE_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const suspendUserTool: ToolConfig<ThriveSuspendUserParams, ThriveUserResponse> = {
id: 'thrive_suspend_user',
name: 'Thrive Suspend User',
description: 'Suspend a user in Thrive by ref, marking the account inactive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
ref: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user ref to suspend',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The date this individual left your organisation (ISO 8601)',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v2')}/users/ref/${encodeURIComponent(params.ref)}/suspend`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => {
const body: Record<string, any> = {}
if (params.endDate) body.endDate = params.endDate
return body
},
},
transformResponse: async (response: Response): Promise<ThriveUserResponse> => {
const data = await parseThriveResponse(response, 'Failed to suspend user')
return { success: true, output: { user: data ?? null } }
},
outputs: {
user: {
type: 'object',
description: 'The suspended user',
properties: THRIVE_USER_LIFECYCLE_OUTPUT_PROPERTIES,
},
},
}
+856
View File
@@ -0,0 +1,856 @@
import type { OutputProperty, ToolResponse } from '@/tools/types'
/**
* Credentials and region shared by every Thrive tool.
* Thrive uses HTTP Basic auth (Tenant ID as username, API key as password).
*/
export interface ThriveBaseParams {
tenantId: string
apiKey: string
/** Region-specific API host, e.g. `public.api.learn.link`. Defaults to Production. */
host?: string
}
export interface ThrivePagination {
totalResults: number
totalPages: number
page: number
perPage: number
}
export const THRIVE_PAGINATION_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
totalResults: { type: 'number', description: 'Total number of results matching the query' },
totalPages: { type: 'number', description: 'Total number of pages available' },
page: { type: 'number', description: 'Current page number' },
perPage: { type: 'number', description: 'Number of results per page' },
}
const USER_POSITION_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'The user ID' },
manager: {
type: 'object',
description: 'Line manager details',
properties: {
id: { type: 'string', description: "The manager's user ID", nullable: true },
name: { type: 'string', description: "The manager's full name", nullable: true },
ref: { type: 'string', description: "The manager's unique reference", nullable: true },
},
},
ouId: { type: 'string', description: 'The organisational unit ID', nullable: true },
isActive: { type: 'boolean', description: 'Whether the position is active' },
startDate: { type: 'string', description: 'Start date (ISO 8601)', nullable: true },
endDate: { type: 'string', description: 'End date (ISO 8601)', nullable: true },
createdAt: { type: 'string', description: 'Creation timestamp (ISO 8601)', nullable: true },
updatedAt: { type: 'string', description: 'Last-update timestamp (ISO 8601)', nullable: true },
}
/** Full `User` schema returned by search-users and get-user-by-id. */
export const THRIVE_USER_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The user's ID" },
ref: { type: 'string', description: "The user's ref", nullable: true },
firstName: { type: 'string', description: "The user's first name", nullable: true },
lastName: { type: 'string', description: "The user's last name", nullable: true },
email: { type: 'string', description: "The user's email", nullable: true },
role: { type: 'string', description: "The user's role", nullable: true },
status: { type: 'string', description: "The user's status", nullable: true },
positions: {
type: 'array',
description: "The user's positions",
items: { type: 'object', properties: USER_POSITION_OUTPUT_PROPERTIES },
},
additionalFields: { type: 'json', description: 'Custom field values', nullable: true },
languageCode: { type: 'string', description: "The user's language code", nullable: true },
deleted: { type: 'boolean', description: 'Whether the user has been deleted' },
compliance: { type: 'number', description: "The user's compliance score" },
level: { type: 'number', description: "The user's level" },
firstLogin: { type: 'string', description: 'First login timestamp (ISO 8601)', nullable: true },
lastLogin: { type: 'string', description: 'Last login timestamp (ISO 8601)', nullable: true },
tags: { type: 'json', description: 'Tag membership (e.g. skills)' },
usersFollowing: {
type: 'array',
description: 'IDs of users this user follows',
items: { type: 'string' },
},
tagsFollowing: {
type: 'array',
description: 'Tags this user follows',
items: { type: 'string' },
},
createdAt: { type: 'string', description: 'Creation timestamp (ISO 8601)', nullable: true },
updatedAt: { type: 'string', description: 'Last-update timestamp (ISO 8601)', nullable: true },
hasPicture: { type: 'boolean', description: 'Whether the user has a profile picture' },
timeZone: { type: 'string', description: "The user's time zone", nullable: true },
summary: { type: 'string', description: "The user's summary", nullable: true },
relevancy: { type: 'number', description: "The user's relevancy score" },
rank: { type: 'json', description: "The user's rank details" },
agreedTerms: {
type: 'boolean',
description: 'Whether the user agreed to the terms',
nullable: true,
},
onboarded: {
type: 'boolean',
description: 'Whether the user has been onboarded',
nullable: true,
},
audiences: {
type: 'array',
description: 'Audience IDs the user belongs to',
items: { type: 'string' },
},
singleSignOn: { type: 'boolean', description: 'Whether the user uses single sign-on' },
}
/** Smaller `BasicUser` schema returned by get-user-by-ref. */
export const THRIVE_BASIC_USER_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: "The user's ID" },
ref: { type: 'string', description: "The user's ref", nullable: true },
firstName: { type: 'string', description: "The user's first name", nullable: true },
lastName: { type: 'string', description: "The user's last name", nullable: true },
email: { type: 'string', description: "The user's email", nullable: true },
role: { type: 'string', description: "The user's role", nullable: true },
status: { type: 'string', description: "The user's status", nullable: true },
positions: {
type: 'array',
description: "The user's positions",
items: { type: 'object', properties: USER_POSITION_OUTPUT_PROPERTIES },
},
additionalFields: { type: 'json', description: 'Custom field values', nullable: true },
languageCode: { type: 'string', description: "The user's language code", nullable: true },
}
/** `UserLifecycleResource` returned by create/update/suspend user. */
export const THRIVE_USER_LIFECYCLE_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'The user ID' },
loginMethod: { type: 'string', description: 'How the user logs in' },
ref: { type: 'string', description: "Your organisation's unique identifier for the user" },
email: { type: 'string', description: 'The email address for the user' },
firstName: { type: 'string', description: 'The given name of the individual' },
lastName: { type: 'string', description: 'The family name of the individual' },
role: { type: 'string', description: 'Role assigned to this individual' },
jobTitle: { type: 'string', description: "Name of this individual's role" },
managerRef: { type: 'string', description: "The line manager's ref", nullable: true },
startDate: { type: 'string', description: 'Date started with the organisation', nullable: true },
endDate: { type: 'string', description: 'Date left the organisation', nullable: true },
timeZone: { type: 'string', description: "The user's preferred timezone" },
languageCode: { type: 'string', description: "The user's preferred language" },
active: { type: 'boolean', description: 'Whether the account is active or suspended' },
createdAt: { type: 'string', description: 'Date/time the user was created' },
updatedAt: { type: 'string', description: 'Date/time the user was last modified' },
sso: { type: 'boolean', description: 'Whether the account is managed by an auth provider' },
domain: {
type: 'string',
description: 'Domain this individual is associated with',
nullable: true,
},
additionalFields: {
type: 'json',
description: 'Custom field values for this user',
nullable: true,
},
}
export const THRIVE_AUDIENCE_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'The id of the audience' },
name: { type: 'string', description: 'The name of the audience' },
reference: { type: 'string', description: 'The external reference for the audience' },
apiControlled: { type: 'boolean', description: 'Whether the audience is API controlled' },
category: { type: 'string', description: 'Either "audience" or "structure"' },
type: { type: 'string', description: 'Either "manual" or "smart"' },
parent: {
type: 'object',
description: 'Parent audience/structure information',
nullable: true,
properties: {
name: { type: 'string', description: 'The name of the parent audience' },
reference: { type: 'string', description: 'The external reference for the parent' },
id: { type: 'string', description: 'The id of the parent audience/structure' },
},
},
createdAt: { type: 'string', description: 'Creation timestamp (ISO 8601)' },
updatedAt: { type: 'string', description: 'Last-update timestamp (ISO 8601)' },
}
export const THRIVE_AUDIENCE_MEMBER_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
userId: { type: 'string', description: "The user's id" },
reference: { type: 'string', description: "The user's reference" },
email: { type: 'string', description: "The user's email" },
}
export const THRIVE_AUDIENCE_MANAGER_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
userId: { type: 'string', description: "The user's id" },
reference: { type: 'string', description: "The user's reference" },
email: { type: 'string', description: "The user's email" },
permissions: {
type: 'object',
description: 'The manager permissions',
properties: {
audienceManager: { type: 'json', description: 'Audience manager permissions' },
peopleManager: { type: 'json', description: 'People manager permissions' },
administrator: {
type: 'json',
description: 'Administrator permissions (structures only)',
nullable: true,
},
},
},
}
/** Superset of SuccessAddUsers / PartialSuccessAddUsers. */
export const THRIVE_ADD_USERS_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
success: {
type: 'object',
description: 'Successfully processed entities',
properties: {
count: { type: 'number', description: 'Number of successfully processed entities' },
entities: {
type: 'array',
description: 'The successfully processed entities',
items: {
type: 'object',
properties: { reference: { type: 'string', description: 'The entity reference' } },
},
},
},
},
failure: {
type: 'object',
description: 'Unsuccessfully processed entities',
optional: true,
properties: {
count: { type: 'number', description: 'Number of unsuccessfully processed entities' },
entities: {
type: 'array',
description: 'The unsuccessfully processed entities',
items: {
type: 'object',
properties: {
reason: { type: 'string', description: 'The reason for the failure' },
reference: { type: 'string', description: 'The entity reference' },
},
},
},
},
},
}
export const THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'The assignment ID' },
audienceId: { type: 'string', description: 'The audience ID' },
primaryContentId: { type: 'string', description: 'The content ID for the primary content' },
alternativeContentIds: {
type: 'array',
description: 'Content IDs that can also complete the assignment',
items: { type: 'string' },
},
hideAlternativeContent: {
type: 'boolean',
description: 'Whether to hide the alternative content',
},
completionPeriod: {
type: 'number',
description: 'Number of days required to complete the assignment',
},
recurrence: {
type: 'number',
description: 'Number of days until the assignment reoccurs',
nullable: true,
},
isActive: { type: 'boolean', description: 'Whether the assignment is active' },
isDeleted: { type: 'boolean', description: 'Whether the assignment is deleted' },
createdAt: { type: 'string', description: 'Creation timestamp (ISO 8601)', nullable: true },
deletedAt: { type: 'string', description: 'Deletion timestamp (ISO 8601)', nullable: true },
updatedAt: { type: 'string', description: 'Last-update timestamp (ISO 8601)', nullable: true },
}
export const THRIVE_ENROLMENT_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'The enrolment ID' },
userId: { type: 'string', description: 'The assignee user ID' },
assignmentId: { type: 'string', description: 'The assignment ID' },
audienceId: { type: 'string', description: 'The audience ID' },
primaryContentId: { type: 'string', description: 'The assigned content ID' },
status: { type: 'string', description: 'Enrolment status' },
availableDate: { type: 'string', description: 'Date a scheduled enrolment becomes open' },
dueDate: { type: 'string', description: 'Date after which a scheduled enrolment is overdue' },
lastCompletedAt: { type: 'string', description: 'Date a scheduled enrolment was last completed' },
history: {
type: 'array',
description: 'Event-log history entries',
items: {
type: 'object',
properties: {
type: { type: 'string', description: 'The type of the logged event' },
completionId: { type: 'string', description: 'The completion ID' },
previousStatus: { type: 'string', description: 'The previous enrolment status' },
nextStatus: { type: 'string', description: 'The next enrolment status' },
createdAt: { type: 'string', description: 'Date the event was logged' },
updatedAt: { type: 'string', description: 'Date the event was last modified' },
},
},
},
updatedAt: { type: 'string', description: 'Date the enrolment was last updated' },
}
export const THRIVE_COMPLETION_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'The completion ID' },
userId: { type: 'string', description: 'The user ID' },
contentId: { type: 'string', description: 'The content ID for the content completed' },
contentVersion: { type: 'number', description: 'The version of the content' },
skills: {
type: 'array',
description: 'The skills acquired by completing this content',
items: { type: 'string' },
},
completionType: { type: 'string', description: 'The type of completion record' },
hadDueDate: { type: 'boolean', description: 'Whether the completion had a due date' },
isRPL: { type: 'boolean', description: 'Whether the completion was imported via RPL' },
completedAt: { type: 'string', description: 'Timestamp when the completion occurred (ISO 8601)' },
activeUntil: {
type: 'string',
description: 'Timestamp the completion is valid until (ISO 8601)',
},
}
const CONTENT_HISTORY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
action: { type: 'string', description: 'Type of change or event recorded' },
timestamp: { type: 'string', description: 'When the action occurred (ISO 8601)' },
performedBy: {
type: 'object',
description: 'The actor that performed the action',
properties: {
type: { type: 'string', description: 'Kind of actor (e.g. user or system)' },
value: { type: 'string', description: 'Identifier or value of the actor' },
},
},
}
export const THRIVE_CONTENT_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
id: { type: 'string', description: 'Unique identifier for the content' },
title: { type: 'string', description: 'Title of the content' },
description: { type: 'string', description: 'Detailed description (may contain HTML)' },
tags: {
type: 'array',
description: 'Tags associated with this content',
items: { type: 'string' },
},
type: { type: 'string', description: 'The kind of artifact associated with this content' },
createdAt: { type: 'string', description: 'Creation timestamp (ISO 8601)' },
updatedAt: { type: 'string', description: 'Last-update timestamp (ISO 8601)' },
author: { type: 'string', description: 'User ID who authored the content', nullable: true },
isOfficial: { type: 'boolean', description: 'Whether the content is recognised as official' },
duration: {
type: 'object',
description: 'Expected time to complete the content',
nullable: true,
properties: {
value: { type: 'number', description: 'Duration value', nullable: true },
unit: { type: 'string', description: "The unit of the duration (always 'minutes')" },
},
},
contentHistory: {
type: 'array',
description: 'Chronological history of actions on this content',
items: { type: 'object', properties: CONTENT_HISTORY_OUTPUT_PROPERTIES },
},
}
export const THRIVE_ACTIVITY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
type: { type: 'string', description: 'The activity action type' },
name: { type: 'string', description: 'The name of the activity' },
id: { type: 'string', description: 'Unique ID for this activity record' },
user: { type: 'string', description: 'User ID who triggered the activity' },
date: { type: 'string', description: 'Timestamp when the activity occurred (ISO 8601)' },
contextId: { type: 'string', description: 'Identifier for the context item' },
contextType: { type: 'string', description: 'What this activity was in relation to' },
data: { type: 'json', description: 'Unstructured activity data; shape varies by type' },
with: { type: 'json', description: 'Additional context information', nullable: true },
}
export const THRIVE_CPD_CATEGORY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
categoryId: { type: 'string', description: 'Unique ID for this category record' },
name: { type: 'string', description: 'Name of the category of CPD activity' },
}
export const THRIVE_CPD_ENTRY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
logEntryId: { type: 'string', description: 'Unique ID for this activity record' },
userId: { type: 'string', description: 'User ID who triggered this activity record' },
activity: {
type: 'object',
description: 'The content item associated with the CPD log entry',
properties: {
type: { type: 'string', description: 'The type of content (e.g. file, article, video)' },
name: { type: 'string', description: 'The name of the content item' },
},
},
category: {
type: 'object',
description: 'The CPD category',
properties: {
categoryId: { type: 'string', description: 'Unique ID for this category record' },
name: { type: 'string', description: 'Name of the category of CPD activity' },
},
},
entryDate: {
type: 'string',
description: 'The date and time the CPD entry was logged (ISO 8601)',
},
durationMinutes: { type: 'number', description: 'Minutes logged as CPD from this activity' },
description: { type: 'string', description: 'Summary or reflective statement', nullable: true },
isVerified: {
type: 'boolean',
description: 'Whether the activity was generated from verified system activity',
},
}
export const THRIVE_CPD_REQUIREMENT_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
audienceRequirementId: { type: 'string', description: 'Unique ID for this requirement record' },
audienceId: { type: 'string', description: 'ID of the audience this requirement applies to' },
requiredMinutes: { type: 'number', description: 'Number of minutes required for CPD completion' },
createdAt: { type: 'string', description: 'Creation timestamp (ISO 8601)' },
updatedAt: { type: 'string', description: 'Last-update timestamp (ISO 8601)', nullable: true },
}
export const THRIVE_CPD_USER_SUMMARY_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
userId: { type: 'string', description: 'ID of the user this summary is for' },
durationMinutes: {
type: 'number',
description: 'Total CPD minutes logged by the user in the period',
},
}
export const THRIVE_TAG_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
tag: { type: 'string', description: 'The name of the tag' },
id: { type: 'string', description: 'The ID of the tag' },
contents: {
type: 'array',
description: 'IDs of contents using this tag',
items: { type: 'string' },
},
campaigns: {
type: 'array',
description: 'IDs of campaigns using this tag',
items: { type: 'string' },
},
interests: {
type: 'array',
description: 'IDs of users interested in this tag',
items: { type: 'string' },
},
skills: {
type: 'array',
description: 'IDs of users skilled in this tag',
items: { type: 'string' },
},
}
export const THRIVE_SKILL_LEVEL_OUTPUT_PROPERTIES: Record<string, OutputProperty> = {
name: { type: 'string', description: 'The name of the skill level' },
isEnabled: { type: 'boolean', description: 'Whether the skill level is enabled' },
value: { type: 'number', description: 'The numeric value of the skill level' },
}
// ─── Users ───────────────────────────────────────────────────────────────────
export interface ThriveCreateUserParams extends ThriveBaseParams {
ref: string
firstName: string
lastName: string
email?: string
loginMethod?: string
role?: string
jobTitle?: string
managerRef?: string
startDate?: string
endDate?: string
timeZone?: string
languageCode?: string
sso?: boolean
domain?: string
additionalFields?: string
}
export interface ThriveUpdateUserParams extends ThriveBaseParams {
ref: string
firstName?: string
lastName?: string
email?: string
loginMethod?: string
role?: string
jobTitle?: string
managerRef?: string
startDate?: string
endDate?: string
timeZone?: string
languageCode?: string
sso?: boolean
domain?: string
additionalFields?: string
}
export interface ThriveDeleteUserParams extends ThriveBaseParams {
ref: string
}
export interface ThriveSuspendUserParams extends ThriveBaseParams {
ref: string
endDate?: string
}
export interface ThriveSearchUsersParams extends ThriveBaseParams {
page?: number
perPage?: number
updatedSince?: string
statuses?: string
omitStatuses?: string
status?: string
}
export interface ThriveGetUserByIdParams extends ThriveBaseParams {
id: string
}
export interface ThriveGetUserByRefParams extends ThriveBaseParams {
ref: string
}
export interface ThriveUserResponse extends ToolResponse {
output: { user: Record<string, any> }
}
export interface ThriveSearchUsersResponse extends ToolResponse {
output: { results: Record<string, any>[]; pagination: ThrivePagination | null }
}
export interface ThriveDeleteResponse extends ToolResponse {
output: { success: boolean }
}
// ─── Audiences ─────────────────────────────────────────────────────────────
export interface ThriveListAudiencesParams extends ThriveBaseParams {
apiControlled?: boolean
updatedSince?: string
page?: number
perPage?: number
}
export interface ThriveCreateAudienceParams extends ThriveBaseParams {
name?: string
reference?: string
parentId?: string
category?: string
}
export interface ThriveGetAudienceParams extends ThriveBaseParams {
audienceId: string
}
export interface ThriveUpdateAudienceParams extends ThriveBaseParams {
audienceId: string
name?: string
reference?: string
parentId?: string
}
export interface ThriveDeleteAudienceParams extends ThriveBaseParams {
audienceId: string
}
export interface ThriveListAudienceMembersParams extends ThriveBaseParams {
audienceId: string
page?: number
perPage?: number
}
export interface ThriveAudienceUsersParams extends ThriveBaseParams {
audienceId: string
users: string
}
export interface ThriveRemoveAudienceMemberParams extends ThriveBaseParams {
audienceId: string
userRef: string
}
export interface ThriveListAudienceManagersParams extends ThriveBaseParams {
audienceId: string
}
export interface ThriveAudienceManagersParams extends ThriveBaseParams {
audienceId: string
managers: string
}
export interface ThriveRemoveAudienceManagerParams extends ThriveBaseParams {
audienceId: string
userId: string
}
export interface ThriveAudienceResponse extends ToolResponse {
output: { audience: Record<string, any> }
}
export interface ThriveListAudiencesResponse extends ToolResponse {
output: { results: Record<string, any>[]; pagination: ThrivePagination | null }
}
export interface ThriveListAudienceMembersResponse extends ToolResponse {
output: { results: Record<string, any>[]; pagination: ThrivePagination | null }
}
export interface ThriveListAudienceManagersResponse extends ToolResponse {
output: { managers: Record<string, any>[] }
}
export interface ThriveAddUsersResponse extends ToolResponse {
output: { result: { success: Record<string, any> | null; failure?: Record<string, any> } }
}
export interface ThriveMessageResponse extends ToolResponse {
output: { status: number; message: string }
}
// ─── Assignments & Enrolments ──────────────────────────────────────────────
export interface ThriveListAssignmentsParams extends ThriveBaseParams {
audienceId?: string
updatedSince?: string
page?: number
perPage?: number
}
export interface ThriveCreateAssignmentParams extends ThriveBaseParams {
audienceId: string
contentId: string
alternativeContentIds?: string
hideAlternativeContent?: boolean
completionPeriod?: number
recurrence?: number
}
export interface ThriveGetAssignmentParams extends ThriveBaseParams {
assignmentId: string
}
export interface ThriveUpdateAssignmentParams extends ThriveBaseParams {
assignmentId: string
audienceId: string
contentId?: string
completionPeriod?: number
recurrence?: number
alternativeContentIds?: string
}
export interface ThriveDeleteAssignmentParams extends ThriveBaseParams {
assignmentId: string
audienceId: string
}
export interface ThriveListEnrolmentsParams extends ThriveBaseParams {
assignmentId: string
updatedAtFrom?: string
updatedAtTo?: string
status?: string
page?: number
perPage?: number
}
export interface ThriveGetEnrolmentParams extends ThriveBaseParams {
assignmentId: string
enrolmentId: string
}
export interface ThriveAssignmentResponse extends ToolResponse {
output: { assignment: Record<string, any> }
}
export interface ThriveListAssignmentsResponse extends ToolResponse {
output: { assignments: Record<string, any>[] }
}
export interface ThriveEnrolmentResponse extends ToolResponse {
output: { enrolment: Record<string, any> }
}
export interface ThriveListEnrolmentsResponse extends ToolResponse {
output: { enrolments: Record<string, any>[] }
}
// ─── Completions ───────────────────────────────────────────────────────────
export interface ThriveListCompletionsParams extends ThriveBaseParams {
contentId?: string
isRPL?: boolean
userId?: string
completedDateRangeStart?: string
completedDateRangeEnd?: string
page?: number
perPage?: number
}
export interface ThriveGetCompletionParams extends ThriveBaseParams {
id: string
}
export interface ThriveCreateCompletionParams extends ThriveBaseParams {
userId: string
contentId: string
completedAt: string
}
export interface ThriveCompletionResponse extends ToolResponse {
output: { completion: Record<string, any> }
}
export interface ThriveListCompletionsResponse extends ToolResponse {
output: { completions: Record<string, any>[] }
}
export interface ThriveCreateCompletionResponse extends ToolResponse {
output: { statementId: string | null }
}
// ─── Content ───────────────────────────────────────────────────────────────
export interface ThriveGetContentParams extends ThriveBaseParams {
id: string
}
export interface ThriveQueryContentParams extends ThriveBaseParams {
page?: number
perPage?: number
types?: string
omitTypes?: string
updatedSince?: string
}
export interface ThriveContentResponse extends ToolResponse {
output: { content: Record<string, any> }
}
export interface ThriveQueryContentResponse extends ToolResponse {
output: { results: Record<string, any>[]; pagination: ThrivePagination | null }
}
// ─── Activities ────────────────────────────────────────────────────────────
export interface ThriveGetActivityParams extends ThriveBaseParams {
id: string
}
export interface ThriveQueryActivitiesParams extends ThriveBaseParams {
page?: number
perPage?: number
actions?: string
omitActions?: string
contentIds?: string
contentType?: string
timestampFrom?: string
timestampTo?: string
}
export interface ThriveActivityResponse extends ToolResponse {
output: { activity: Record<string, any> }
}
export interface ThriveQueryActivitiesResponse extends ToolResponse {
output: { results: Record<string, any>[]; pagination: ThrivePagination | null }
}
// ─── CPD ───────────────────────────────────────────────────────────────────
export interface ThriveGetCpdCategoryParams extends ThriveBaseParams {
categoryId: string
}
export interface ThriveQueryCpdCategoriesParams extends ThriveBaseParams {
page?: number
perPage?: number
updatedSince?: string
}
export interface ThriveGetCpdEntryParams extends ThriveBaseParams {
logEntryId: string
}
export interface ThriveQueryCpdEntriesParams extends ThriveBaseParams {
page?: number
perPage?: number
entryDateFrom?: string
entryDateTo?: string
}
export interface ThriveGetCpdRequirementParams extends ThriveBaseParams {
audienceRequirementId: string
}
export interface ThriveQueryCpdRequirementsParams extends ThriveBaseParams {
page?: number
perPage?: number
updatedSince?: string
}
export interface ThriveQueryCpdUserSummariesParams extends ThriveBaseParams {
entryDateFrom: string
entryDateTo: string
userIds?: string
page?: number
perPage?: number
}
export interface ThriveCpdCategoryResponse extends ToolResponse {
output: { category: Record<string, any> }
}
export interface ThriveCpdEntryResponse extends ToolResponse {
output: { entry: Record<string, any> }
}
export interface ThriveCpdRequirementResponse extends ToolResponse {
output: { requirement: Record<string, any> }
}
export interface ThriveCpdPaginatedResponse extends ToolResponse {
output: { results: Record<string, any>[]; pagination: ThrivePagination | null }
}
// ─── Tags & Skills ─────────────────────────────────────────────────────────
export interface ThriveListTagsParams extends ThriveBaseParams {
page?: number
perPage?: number
updatedSince?: string
}
export interface ThriveGetTagParams extends ThriveBaseParams {
tagId: string
}
export interface ThriveAddUserTagsParams extends ThriveBaseParams {
userId: string
tags: string
}
export interface ThriveRemoveUserTagsParams extends ThriveBaseParams {
userId: string
tags: string
}
export interface ThriveUpdateUserSkillsParams extends ThriveBaseParams {
userId: string
skills: string
}
export interface ThriveGetSkillLevelsParams extends ThriveBaseParams {}
export interface ThriveTagResponse extends ToolResponse {
output: { tag: Record<string, any> }
}
export interface ThriveListTagsResponse extends ToolResponse {
output: { results: Record<string, any>[]; pagination: ThrivePagination | null }
}
export interface ThriveSkillLevelsResponse extends ToolResponse {
output: { levels: Record<string, any>[] }
}
+111
View File
@@ -0,0 +1,111 @@
import type { ThriveAssignmentResponse, ThriveUpdateAssignmentParams } from '@/tools/thrive/types'
import { THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const updateAssignmentTool: ToolConfig<
ThriveUpdateAssignmentParams,
ThriveAssignmentResponse
> = {
id: 'thrive_update_assignment',
name: 'Thrive Update Assignment',
description: 'Update a compliance assignment in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
assignmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The assignment ID',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience ID',
},
contentId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The content ID for the primary content',
},
completionPeriod: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The number of days required to complete the assignment',
},
recurrence: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'The number of days until the assignment will reoccur',
},
alternativeContentIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON array of content IDs that can also complete the assignment',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/assignments/${encodeURIComponent(params.assignmentId)}`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => {
const body: Record<string, any> = {
audienceId: params.audienceId,
}
if (params.contentId) body.contentId = params.contentId
if (params.completionPeriod !== undefined) body.completionPeriod = params.completionPeriod
if (params.recurrence !== undefined) body.recurrence = params.recurrence
if (params.alternativeContentIds) {
body.alternativeContentIds = parseThriveArray<string>(
params.alternativeContentIds,
'alternativeContentIds'
)
}
return body
},
},
transformResponse: async (response: Response): Promise<ThriveAssignmentResponse> => {
const data = await parseThriveResponse(response, 'Failed to update assignment')
return { success: true, output: { assignment: data ?? null } }
},
outputs: {
assignment: {
type: 'object',
description: 'The updated assignment',
properties: THRIVE_ASSIGNMENT_OUTPUT_PROPERTIES,
},
},
}
+83
View File
@@ -0,0 +1,83 @@
import type { ThriveAudienceResponse, ThriveUpdateAudienceParams } from '@/tools/thrive/types'
import { THRIVE_AUDIENCE_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import { getThriveBaseUrl, getThriveHeaders, parseThriveResponse } from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const updateAudienceTool: ToolConfig<ThriveUpdateAudienceParams, ThriveAudienceResponse> = {
id: 'thrive_update_audience',
name: 'Thrive Update Audience',
description: 'Update an audience in Thrive, optionally moving it to a new parent.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
audienceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The audience id or audience reference',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The name of the audience (max 100 characters)',
},
reference: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The external reference for the audience (max 100 characters)',
},
parentId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The id of the parent audience/structure to move the audience to',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/audiences/${encodeURIComponent(params.audienceId)}`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => {
const body: Record<string, any> = {}
if (params.name) body.name = params.name
if (params.reference) body.reference = params.reference
if (params.parentId) body.parentId = params.parentId
return body
},
},
transformResponse: async (response: Response): Promise<ThriveAudienceResponse> => {
const data = await parseThriveResponse(response, 'Failed to update audience')
return { success: true, output: { audience: data ?? null } }
},
outputs: {
audience: {
type: 'object',
description: 'The updated audience',
properties: THRIVE_AUDIENCE_OUTPUT_PROPERTIES,
},
},
}
+167
View File
@@ -0,0 +1,167 @@
import type { ThriveUpdateUserParams, ThriveUserResponse } from '@/tools/thrive/types'
import { THRIVE_USER_LIFECYCLE_OUTPUT_PROPERTIES } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveJsonObject,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const updateUserTool: ToolConfig<ThriveUpdateUserParams, ThriveUserResponse> = {
id: 'thrive_update_user',
name: 'Thrive Update User',
description: 'Update an existing user in Thrive by ref. Only the fields provided are changed.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
ref: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The user ref to update',
},
firstName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The given name of the individual',
},
lastName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The family name of the individual',
},
email: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The email address for the user',
},
loginMethod: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "How the user logs in: 'email' or 'ref'",
},
role: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "Role assigned: 'administrator', 'learneradmin', or 'learner'",
},
jobTitle: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "Name of this individual's role in your organisation",
},
managerRef: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "Your organisation's unique identifier for this individual's line manager",
},
startDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date this individual started with your organisation (ISO 8601)',
},
endDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Date this individual left your organisation (ISO 8601)',
},
timeZone: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "The user's preferred timezone",
},
languageCode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: "The user's preferred language (e.g. 'en-gb')",
},
sso: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether the account is managed by an authentication provider',
},
domain: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Domain this individual is associated with',
},
additionalFields: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON object of custom field key-value pairs. Example: {"department":"Sales"}',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v2')}/users/ref/${encodeURIComponent(params.ref)}`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => {
const body: Record<string, any> = {}
if (params.firstName !== undefined) body.firstName = params.firstName
if (params.lastName !== undefined) body.lastName = params.lastName
if (params.email !== undefined) body.email = params.email
if (params.loginMethod !== undefined) body.loginMethod = params.loginMethod
if (params.role !== undefined) body.role = params.role
if (params.jobTitle !== undefined) body.jobTitle = params.jobTitle
if (params.managerRef !== undefined) body.managerRef = params.managerRef
if (params.startDate !== undefined) body.startDate = params.startDate
if (params.endDate !== undefined) body.endDate = params.endDate
if (params.timeZone !== undefined) body.timeZone = params.timeZone
if (params.languageCode !== undefined) body.languageCode = params.languageCode
if (params.sso !== undefined) body.sso = params.sso
if (params.domain !== undefined) body.domain = params.domain
if (params.additionalFields) {
body.additionalFields = parseThriveJsonObject(params.additionalFields, 'additionalFields')
}
return body
},
},
transformResponse: async (response: Response): Promise<ThriveUserResponse> => {
const data = await parseThriveResponse(response, 'Failed to update user')
return { success: true, output: { user: data ?? null } }
},
outputs: {
user: {
type: 'object',
description: 'The updated user',
properties: THRIVE_USER_LIFECYCLE_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,75 @@
import type { ThriveMessageResponse, ThriveUpdateUserSkillsParams } from '@/tools/thrive/types'
import {
getThriveBaseUrl,
getThriveHeaders,
parseThriveArray,
parseThriveResponse,
} from '@/tools/thrive/utils'
import type { ToolConfig } from '@/tools/types'
export const updateUserSkillsTool: ToolConfig<ThriveUpdateUserSkillsParams, ThriveMessageResponse> =
{
id: 'thrive_update_user_skills',
name: 'Thrive Update User Skills',
description: 'Update skills and levels for a learner in Thrive.',
version: '1.0.0',
params: {
tenantId: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive Tenant ID (used as the Basic auth username)',
},
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Thrive API key (used as the Basic auth password)',
},
host: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Region-specific API host',
},
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The learner ID',
},
skills: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'JSON array of skill objects (1-100). Each: {"tagName":"leadership","level":1,"targetLevel":3}. level/targetLevel optional (min -1).',
},
},
request: {
url: (params) =>
`${getThriveBaseUrl(params.host, 'v1')}/users/${encodeURIComponent(params.userId)}/skills`,
method: 'PATCH',
headers: (params) => getThriveHeaders(params.tenantId, params.apiKey),
body: (params) => ({
op: 'update',
path: 'skills',
value: parseThriveArray(params.skills, 'skills'),
}),
},
transformResponse: async (response: Response): Promise<ThriveMessageResponse> => {
const data = await parseThriveResponse(response, 'Failed to update skills for learner')
return {
success: true,
output: { status: data?.status ?? null, message: data?.message ?? null },
}
},
outputs: {
status: { type: 'number', description: 'The HTTP status code of the operation' },
message: { type: 'string', description: 'A human-readable result message' },
},
}
+106
View File
@@ -0,0 +1,106 @@
/**
* Default Thrive API host (Production, all regions except MEA).
* The Thrive REST API is reached at `https://{host}/rest/{version}`.
*/
export const THRIVE_DEFAULT_HOST = 'public.api.learn.link'
/**
* Builds the base REST URL for a Thrive API request.
*
* @param host - The region-specific API host (e.g. `public.api.learn.link`).
* @param version - The API version: `v1` for most resources, `v2` for user lifecycle.
*/
export function getThriveBaseUrl(host: string | undefined, version: 'v1' | 'v2'): string {
const resolvedHost = host?.trim() || THRIVE_DEFAULT_HOST
return `https://${resolvedHost}/rest/${version}`
}
/**
* Builds the HTTP Basic authentication headers for a Thrive API request.
* The Tenant ID is used as the username and the API key as the password.
*/
export function getThriveHeaders(tenantId: string, apiKey: string): Record<string, string> {
return {
Authorization: `Basic ${btoa(`${tenantId}:${apiKey}`)}`,
'Content-Type': 'application/json',
Accept: 'application/json',
}
}
/**
* Appends a query parameter to a URL when the value is defined and non-empty.
* Numbers are coerced to strings; empty strings and `undefined`/`null` are skipped.
*/
export function appendThriveQuery(
url: URL,
key: string,
value: string | number | boolean | undefined | null
): void {
if (value === undefined || value === null) return
const stringValue = typeof value === 'string' ? value.trim() : String(value)
if (stringValue === '') return
url.searchParams.set(key, stringValue)
}
/**
* Parses a value that may be a JSON array string (from LLM/user input) or an
* already-parsed array into a typed array. An empty/whitespace string yields an
* empty array; malformed JSON throws so the caller sees a clear error rather
* than silently sending an empty collection.
*/
export function parseThriveArray<T = unknown>(value: unknown, fieldName = 'array'): T[] {
if (Array.isArray(value)) return value as T[]
if (typeof value === 'string') {
const trimmed = value.trim()
if (trimmed === '') return []
let parsed: unknown
try {
parsed = JSON.parse(trimmed)
} catch {
throw new Error(`Invalid JSON provided for ${fieldName}: expected a JSON array`)
}
return Array.isArray(parsed) ? (parsed as T[]) : [parsed as T]
}
return []
}
/**
* Parses a JSON object string (from LLM/user input), throwing a descriptive
* error on malformed JSON so it is never silently dropped.
*/
export function parseThriveJsonObject(value: string, fieldName: string): Record<string, unknown> {
try {
return JSON.parse(value)
} catch {
throw new Error(`Invalid JSON provided for ${fieldName}: expected a JSON object`)
}
}
/**
* Reads a Thrive API response, throwing a descriptive error on non-2xx status.
* Tolerates empty bodies (returned by some delete endpoints) and non-JSON bodies.
*/
export async function parseThriveResponse<T = any>(
response: Response,
fallbackError: string
): Promise<T> {
const text = await response.text()
let data: any = {}
if (text) {
try {
data = JSON.parse(text)
} catch {
data = { raw: text }
}
}
if (!response.ok) {
const message =
(data && typeof data.message === 'string' && data.message) ||
(data && typeof data.error === 'string' && data.error) ||
fallbackError
throw new Error(message)
}
return data as T
}