@arbium/enterprise-agent-connect 0.1.1 → 0.1.2-dev.d2aa5ca
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -10
- package/dist/connectors/dell-techdirect/index.d.ts +8 -0
- package/dist/connectors/dell-techdirect/tools.d.ts +2 -0
- package/dist/connectors/dell-techdirect/vendor.d.ts +6 -0
- package/dist/connectors/dynamics-365/connector.json +213 -0
- package/dist/connectors/dynamics-365/index.d.ts +11 -0
- package/dist/connectors/dynamics-365/index.js +10 -0
- package/dist/connectors/dynamics-365/index.js.map +1 -0
- package/dist/connectors/dynamics-365/tools.d.ts +35 -0
- package/dist/connectors/dynamics-365/tools.js +806 -0
- package/dist/connectors/dynamics-365/tools.js.map +1 -0
- package/dist/connectors/dynamics-365/vendor.d.ts +9 -0
- package/dist/connectors/dynamics-365/vendor.js +110 -0
- package/dist/connectors/dynamics-365/vendor.js.map +1 -0
- package/dist/connectors/entra/index.d.ts +2 -0
- package/dist/connectors/entra/tools.d.ts +14 -0
- package/dist/connectors/fedex/index.d.ts +8 -0
- package/dist/connectors/fedex/tools.d.ts +3 -0
- package/dist/connectors/fedex/vendor.d.ts +7 -0
- package/dist/connectors/gong/connector.json +127 -0
- package/dist/connectors/gong/index.d.ts +8 -0
- package/dist/connectors/gong/index.js +7 -0
- package/dist/connectors/gong/index.js.map +1 -0
- package/dist/connectors/gong/tools.d.ts +8 -0
- package/dist/connectors/gong/tools.js +424 -0
- package/dist/connectors/gong/tools.js.map +1 -0
- package/dist/connectors/gong/vendor.d.ts +4 -0
- package/dist/connectors/gong/vendor.js +97 -0
- package/dist/connectors/gong/vendor.js.map +1 -0
- package/dist/connectors/http/index.d.ts +38 -0
- package/dist/connectors/http/index.js +151 -64
- package/dist/connectors/http/index.js.map +1 -1
- package/dist/connectors/intune/index.d.ts +2 -0
- package/dist/connectors/intune/tools.d.ts +12 -0
- package/dist/connectors/jamf/connector.json +182 -0
- package/dist/connectors/jamf/index.d.ts +8 -0
- package/dist/connectors/jamf/index.js +7 -0
- package/dist/connectors/jamf/index.js.map +1 -0
- package/dist/connectors/jamf/tools.d.ts +7 -0
- package/dist/connectors/jamf/tools.js +659 -0
- package/dist/connectors/jamf/tools.js.map +1 -0
- package/dist/connectors/jamf/vendor.d.ts +5 -0
- package/dist/connectors/jamf/vendor.js +66 -0
- package/dist/connectors/jamf/vendor.js.map +1 -0
- package/dist/connectors/jira/connector.json +144 -1
- package/dist/connectors/jira/index.d.ts +8 -0
- package/dist/connectors/jira/jql.d.ts +4 -0
- package/dist/connectors/jira/tools.d.ts +3 -0
- package/dist/connectors/jira/vendor.d.ts +3 -0
- package/dist/connectors/microsoft/client.d.ts +58 -0
- package/dist/connectors/netsuite/connector.json +315 -0
- package/dist/connectors/netsuite/index.d.ts +8 -0
- package/dist/connectors/netsuite/index.js +7 -0
- package/dist/connectors/netsuite/index.js.map +1 -0
- package/dist/connectors/netsuite/tools.d.ts +24 -0
- package/dist/connectors/netsuite/tools.js +447 -0
- package/dist/connectors/netsuite/tools.js.map +1 -0
- package/dist/connectors/netsuite/vendor.d.ts +26 -0
- package/dist/connectors/netsuite/vendor.js +248 -0
- package/dist/connectors/netsuite/vendor.js.map +1 -0
- package/dist/connectors/odata/index.d.ts +36 -0
- package/dist/connectors/odata/index.js +460 -0
- package/dist/connectors/odata/index.js.map +1 -0
- package/dist/connectors/okta/connector.json +193 -0
- package/dist/connectors/okta/index.d.ts +8 -0
- package/dist/connectors/okta/index.js +7 -0
- package/dist/connectors/okta/index.js.map +1 -0
- package/dist/connectors/okta/tools.d.ts +6 -0
- package/dist/connectors/okta/tools.js +429 -0
- package/dist/connectors/okta/tools.js.map +1 -0
- package/dist/connectors/okta/vendor.d.ts +14 -0
- package/dist/connectors/okta/vendor.js +203 -0
- package/dist/connectors/okta/vendor.js.map +1 -0
- package/dist/connectors/outlook-calendar/index.d.ts +2 -0
- package/dist/connectors/outlook-calendar/tools.d.ts +65 -0
- package/dist/connectors/outlook-mail/index.d.ts +2 -0
- package/dist/connectors/outlook-mail/tools.d.ts +8 -0
- package/dist/connectors/salesforce/index.d.ts +8 -0
- package/dist/connectors/salesforce/soql.d.ts +3 -0
- package/dist/connectors/salesforce/tools.d.ts +9 -0
- package/dist/connectors/salesforce/vendor.d.ts +3 -0
- package/dist/connectors/sap-s4hana/connector.json +263 -0
- package/dist/connectors/sap-s4hana/index.d.ts +8 -0
- package/dist/connectors/sap-s4hana/index.js +7 -0
- package/dist/connectors/sap-s4hana/index.js.map +1 -0
- package/dist/connectors/sap-s4hana/tools.d.ts +4 -0
- package/dist/connectors/sap-s4hana/tools.js +761 -0
- package/dist/connectors/sap-s4hana/tools.js.map +1 -0
- package/dist/connectors/sap-s4hana/vendor.d.ts +5 -0
- package/dist/connectors/sap-s4hana/vendor.js +176 -0
- package/dist/connectors/sap-s4hana/vendor.js.map +1 -0
- package/dist/connectors/servicenow/connector.json +228 -0
- package/dist/connectors/servicenow/index.d.ts +8 -0
- package/dist/connectors/servicenow/index.js +7 -0
- package/dist/connectors/servicenow/index.js.map +1 -0
- package/dist/connectors/servicenow/tools.d.ts +4 -0
- package/dist/connectors/servicenow/tools.js +884 -0
- package/dist/connectors/servicenow/tools.js.map +1 -0
- package/dist/connectors/servicenow/vendor.d.ts +4 -0
- package/dist/connectors/servicenow/vendor.js +109 -0
- package/dist/connectors/servicenow/vendor.js.map +1 -0
- package/dist/connectors/sharepoint-files/excel.d.ts +16 -0
- package/dist/connectors/sharepoint-files/index.d.ts +11 -0
- package/dist/connectors/sharepoint-files/tools.d.ts +52 -0
- package/dist/connectors/sharepoint-files/vendor.d.ts +11 -0
- package/dist/connectors/slack/connector.json +148 -0
- package/dist/connectors/slack/index.d.ts +8 -0
- package/dist/connectors/slack/index.js +7 -0
- package/dist/connectors/slack/index.js.map +1 -0
- package/dist/connectors/slack/tools.d.ts +3 -0
- package/dist/connectors/slack/tools.js +355 -0
- package/dist/connectors/slack/tools.js.map +1 -0
- package/dist/connectors/slack/vendor.d.ts +17 -0
- package/dist/connectors/slack/vendor.js +195 -0
- package/dist/connectors/slack/vendor.js.map +1 -0
- package/dist/connectors/soap/index.d.ts +19 -0
- package/dist/connectors/soap/index.js +248 -0
- package/dist/connectors/soap/index.js.map +1 -0
- package/dist/connectors/soap/xml.d.ts +12 -0
- package/dist/connectors/soap/xml.js +126 -0
- package/dist/connectors/soap/xml.js.map +1 -0
- package/dist/connectors/sql/engines.d.ts +58 -0
- package/dist/connectors/sql/engines.js +292 -0
- package/dist/connectors/sql/engines.js.map +1 -0
- package/dist/connectors/sql/index.d.ts +19 -0
- package/dist/connectors/sql/index.js +212 -0
- package/dist/connectors/sql/index.js.map +1 -0
- package/dist/connectors/teams/index.d.ts +2 -0
- package/dist/connectors/teams/tools.d.ts +2 -0
- package/dist/connectors/workday/connector.json +186 -0
- package/dist/connectors/workday/index.d.ts +8 -0
- package/dist/connectors/workday/index.js +7 -0
- package/dist/connectors/workday/index.js.map +1 -0
- package/dist/connectors/workday/tools.d.ts +33 -0
- package/dist/connectors/workday/tools.js +410 -0
- package/dist/connectors/workday/tools.js.map +1 -0
- package/dist/connectors/workday/vendor.d.ts +18 -0
- package/dist/connectors/workday/vendor.js +195 -0
- package/dist/connectors/workday/vendor.js.map +1 -0
- package/dist/packages/connector-kit/src/branding.d.ts +57 -0
- package/dist/packages/connector-kit/src/certificate.d.ts +19 -0
- package/dist/packages/connector-kit/src/common.d.ts +40 -0
- package/dist/packages/connector-kit/src/connector.d.ts +1346 -0
- package/dist/packages/connector-kit/src/connector.js +586 -44
- package/dist/packages/connector-kit/src/connector.js.map +1 -1
- package/dist/packages/connector-kit/src/index.d.ts +5 -0
- package/dist/packages/connector-kit/src/index.js +5 -0
- package/dist/packages/connector-kit/src/index.js.map +1 -0
- package/dist/packages/connector-kit/src/oauth.d.ts +15 -0
- package/dist/packages/connector-kit/src/oauth.js +21 -4
- package/dist/packages/connector-kit/src/oauth.js.map +1 -1
- package/dist/packages/connector-kit/src/types.d.ts +85 -0
- package/dist/packages/connector-kit/src/types.js.map +1 -1
- package/dist/packages/server/migrations/0007_app_events.sql +110 -0
- package/dist/packages/server/migrations/rollback/to-legacy.sql +3 -0
- package/dist/packages/server/src/api.d.ts +3714 -0
- package/dist/packages/server/src/api.js +135 -1
- package/dist/packages/server/src/api.js.map +1 -1
- package/dist/packages/server/src/app.d.ts +23 -0
- package/dist/packages/server/src/app.js +24 -1
- package/dist/packages/server/src/app.js.map +1 -1
- package/dist/packages/server/src/builtin.d.ts +4 -0
- package/dist/packages/server/src/builtin.js +18 -0
- package/dist/packages/server/src/builtin.js.map +1 -1
- package/dist/packages/server/src/consent.d.ts +27 -0
- package/dist/packages/server/src/events/admin.d.ts +156 -0
- package/dist/packages/server/src/events/admin.js +255 -0
- package/dist/packages/server/src/events/admin.js.map +1 -0
- package/dist/packages/server/src/events/deliver.d.ts +43 -0
- package/dist/packages/server/src/events/deliver.js +129 -0
- package/dist/packages/server/src/events/deliver.js.map +1 -0
- package/dist/packages/server/src/events/runtime.d.ts +28 -0
- package/dist/packages/server/src/events/runtime.js +397 -0
- package/dist/packages/server/src/events/runtime.js.map +1 -0
- package/dist/packages/server/src/events/store.d.ts +172 -0
- package/dist/packages/server/src/events/store.js +275 -0
- package/dist/packages/server/src/events/store.js.map +1 -0
- package/dist/packages/server/src/index.d.ts +40 -0
- package/dist/packages/server/src/index.js +67 -11
- package/dist/packages/server/src/index.js.map +1 -1
- package/dist/packages/server/src/migrate.d.ts +11 -0
- package/dist/packages/server/src/openapi.d.ts +4 -0
- package/dist/packages/server/src/openapi.js +2 -2
- package/dist/packages/server/src/openapi.js.map +1 -1
- package/dist/packages/server/src/queue.d.ts +10 -0
- package/dist/packages/server/src/queue.js +45 -0
- package/dist/packages/server/src/queue.js.map +1 -0
- package/dist/packages/server/src/secrets.d.ts +19 -0
- package/dist/packages/server/src/server.d.ts +1 -0
- package/dist/packages/server/src/server.js +14 -1
- package/dist/packages/server/src/server.js.map +1 -1
- package/dist/packages/server/src/service.d.ts +760 -0
- package/dist/packages/server/src/service.js +10 -0
- package/dist/packages/server/src/service.js.map +1 -1
- package/dist/packages/server/src/store.d.ts +158 -0
- package/dist/packages/server/src/store.js +4 -0
- package/dist/packages/server/src/store.js.map +1 -1
- package/dist/packages/server/src/teams/activity.d.ts +123 -0
- package/dist/packages/server/src/teams/activity.js +6 -5
- package/dist/packages/server/src/teams/activity.js.map +1 -1
- package/dist/packages/server/src/teams/admin.d.ts +335 -0
- package/dist/packages/server/src/teams/admin.js +1 -1
- package/dist/packages/server/src/teams/admin.js.map +1 -1
- package/dist/packages/server/src/teams/approval.d.ts +57 -0
- package/dist/packages/server/src/teams/bot.d.ts +25 -0
- package/dist/packages/server/src/teams/claude.d.ts +46 -0
- package/dist/packages/server/src/teams/jwt.d.ts +17 -0
- package/dist/packages/server/src/teams/package.d.ts +79 -0
- package/dist/packages/server/src/teams/provision.d.ts +84 -0
- package/dist/packages/server/src/teams/runner.d.ts +80 -0
- package/dist/packages/server/src/teams/runner.js +50 -6
- package/dist/packages/server/src/teams/runner.js.map +1 -1
- package/dist/packages/server/src/teams/runtime.d.ts +91 -0
- package/dist/packages/server/src/teams/runtime.js +25 -47
- package/dist/packages/server/src/teams/runtime.js.map +1 -1
- package/dist/packages/server/src/teams/store.d.ts +233 -0
- package/package.json +28 -2
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "workday",
|
|
3
|
+
"name": "Workday",
|
|
4
|
+
"description": "Let agents look up workers, managers and organizations, read time off, and run the Workday reports you choose. Pay and personal data stay out unless a report you add includes them.",
|
|
5
|
+
"logo": "/brand/registry/workday.svg",
|
|
6
|
+
"identity": "An integration system user named \"{brand.microsoft.appName}\" in a security group of its own, signing in through an API client for integrations.",
|
|
7
|
+
"accountKey": "account",
|
|
8
|
+
"connectionKind": "guided",
|
|
9
|
+
"setup": [
|
|
10
|
+
{
|
|
11
|
+
"title": "Create an integration system user",
|
|
12
|
+
"body": "In Workday, create an integration system user named \"{brand.microsoft.appName}\" that cannot sign in to the Workday website. Give it a long random password; it is never typed again. Then exempt it from password expiry, so the connection does not stop when the password would expire.",
|
|
13
|
+
"click": [
|
|
14
|
+
"Search: Create Integration System User > User Name: {brand.microsoft.appName} > Session Timeout Minutes: 0 > Do Not Allow UI Sessions: on > OK",
|
|
15
|
+
"Search: Maintain Password Rules > System Users exempt from password expiration > add {brand.microsoft.appName} > OK"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"title": "Put it in a security group of its own",
|
|
20
|
+
"body": "Create an integration system security group and add the user to it. Choose Constrained if Workday itself should also keep the account to some organizations; Unconstrained reaches every worker your domain permissions allow, and you can still narrow each agent to organizations here.",
|
|
21
|
+
"click": [
|
|
22
|
+
"Search: Create Security Group > Type: Integration System Security Group (Unconstrained) or (Constrained) > Name: {brand.microsoft.appName} > OK",
|
|
23
|
+
"Integration System Users: {brand.microsoft.appName} > OK"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"title": "Give the group these domain permissions",
|
|
28
|
+
"body": "Give the security group View (Get) on the domains below, or Modify (Put) where it says so, then activate the pending security policy changes. Without them Workday answers with empty lists or refuses the call.",
|
|
29
|
+
"click": [
|
|
30
|
+
"Search: Maintain Permissions for Security Group > {brand.microsoft.appName} > Domain Security Policy Permissions > add each domain below",
|
|
31
|
+
"Search: Activate Pending Security Policy Changes > Comment: {brand.microsoft.appName} > OK > Confirm > OK"
|
|
32
|
+
],
|
|
33
|
+
"permissions": true
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"title": "Register an API client for integrations",
|
|
37
|
+
"body": "Register an API client for integrations named \"{brand.microsoft.appName}\" with non-expiring refresh tokens and these functional area scopes. Copy the client ID and secret: Workday shows the secret only once.",
|
|
38
|
+
"click": [
|
|
39
|
+
"Search: Register API Client for Integrations > Client Name: {brand.microsoft.appName} > Non-Expiring Refresh Tokens: on > Scope (Functional Areas): the areas below > OK"
|
|
40
|
+
],
|
|
41
|
+
"copy": ["{scope}"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"title": "Make its refresh token",
|
|
45
|
+
"body": "Make a refresh token that signs the API client in as the integration system user, and copy it. Also copy the Workday REST API Endpoint shown at the top of View API Clients; it names your tenant.",
|
|
46
|
+
"click": [
|
|
47
|
+
"Search: View API Clients > API Clients for Integrations > {brand.microsoft.appName} > Related Actions > API Client > Manage Refresh Tokens for Integrations",
|
|
48
|
+
"Workday Account: {brand.microsoft.appName} > Generate New Refresh Token: on > OK > copy the refresh token"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"title": "Add reports (optional)",
|
|
53
|
+
"body": "Most companies keep their own data, such as open job requisitions, headcount or cost centers, in custom reports. For each report agents may run: make it an advanced report enabled as a web service, share it with the integration system user, and copy its JSON link. Any prompts the report has become filters agents can set. Agents see every column the report has, so leave out pay, national IDs and anything else they should not read.",
|
|
54
|
+
"click": [
|
|
55
|
+
"The report > Related Actions > Custom Report > Edit > Advanced > Enable As Web Service: on",
|
|
56
|
+
"Share > Share with specific authorized groups and users: {brand.microsoft.appName} > OK",
|
|
57
|
+
"The report > Related Actions > Web Service > View URLs > JSON > copy the link"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"afterConnect": [],
|
|
62
|
+
"fields": [
|
|
63
|
+
{
|
|
64
|
+
"id": "endpoint",
|
|
65
|
+
"label": "Workday REST API endpoint",
|
|
66
|
+
"help": "Shown at the top of View API Clients in Workday.",
|
|
67
|
+
"placeholder": "https://wd5-services1.myworkday.com/ccx/api/v1/acme",
|
|
68
|
+
"secret": false
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "client_id",
|
|
72
|
+
"label": "Client ID",
|
|
73
|
+
"secret": false
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "client_secret",
|
|
77
|
+
"label": "Client secret",
|
|
78
|
+
"secret": true
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "refresh_token",
|
|
82
|
+
"label": "Refresh token",
|
|
83
|
+
"secret": true
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "reports",
|
|
87
|
+
"label": "Reports",
|
|
88
|
+
"help": "Optional. Each report's JSON link from Workday, separated by spaces or new lines. Leave empty for none.",
|
|
89
|
+
"placeholder": "https://wd5-services1.myworkday.com/ccx/service/customreport2/acme/jsmith/Open_Requisitions?format=json",
|
|
90
|
+
"secret": false
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "report_org_column",
|
|
94
|
+
"label": "Organization column in reports",
|
|
95
|
+
"help": "Optional. The column holding each row's organization Workday ID, in every report above. Agents narrowed to some organizations see only their rows, and cannot run reports while this is empty.",
|
|
96
|
+
"placeholder": "Supervisory_Organization_ID",
|
|
97
|
+
"secret": false
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"capabilities": [
|
|
101
|
+
{
|
|
102
|
+
"id": "workers",
|
|
103
|
+
"label": "Look up workers",
|
|
104
|
+
"description": "Find workers and read their title, organization, location, work email, manager chain and direct reports, and read supervisory organizations. No pay or personal data.",
|
|
105
|
+
"required": true,
|
|
106
|
+
"scopes": ["Staffing", "Organizations and Roles"],
|
|
107
|
+
"permissions": [
|
|
108
|
+
"Worker Data: Public Worker Reports (View)",
|
|
109
|
+
"Reports: Organization (View)",
|
|
110
|
+
"Reports: Manager (View)"
|
|
111
|
+
],
|
|
112
|
+
"forbidden": "The integration system user's security group needs View on Worker Data: Public Worker Reports, Reports: Organization and Reports: Manager, and the API client the Staffing and Organizations and Roles scopes.",
|
|
113
|
+
"tools": [
|
|
114
|
+
"workday_search_workers",
|
|
115
|
+
"workday_get_worker",
|
|
116
|
+
"workday_list_direct_reports",
|
|
117
|
+
"workday_get_management_chain",
|
|
118
|
+
"workday_get_organization",
|
|
119
|
+
"workday_list_organization_workers"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "time_off",
|
|
124
|
+
"label": "Read time off",
|
|
125
|
+
"description": "Read workers' time off balances and their requested, approved and taken time off.",
|
|
126
|
+
"scopes": ["Time Off and Leave"],
|
|
127
|
+
"permissions": [
|
|
128
|
+
"Worker Data: Time Off (Time Off) (View)",
|
|
129
|
+
"Worker Data: Time Off (Time Off Balances) (View)"
|
|
130
|
+
],
|
|
131
|
+
"forbidden": "The integration system user's security group needs View on Worker Data: Time Off (Time Off) and Worker Data: Time Off (Time Off Balances), and the API client the Time Off and Leave scope.",
|
|
132
|
+
"tools": ["workday_get_time_off_balances", "workday_list_time_off"]
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": "request_time_off",
|
|
136
|
+
"label": "Request time off",
|
|
137
|
+
"description": "Submit time off requests for workers. Each request goes through your Request Time Off approvals as if the worker had asked.",
|
|
138
|
+
"note": "Agents with this can submit requests in any allowed worker's name. Keep each agent to the organizations it needs.",
|
|
139
|
+
"scopes": ["Time Off and Leave"],
|
|
140
|
+
"permissions": [
|
|
141
|
+
"Request Time Off (REST Service) (Modify)",
|
|
142
|
+
"Request Time Off business process: let the security group initiate it"
|
|
143
|
+
],
|
|
144
|
+
"forbidden": "The integration system user's security group needs Modify on Request Time Off (REST Service) and may need to be allowed to initiate the Request Time Off business process.",
|
|
145
|
+
"tools": ["workday_list_time_off_types", "workday_request_time_off"]
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "reports",
|
|
149
|
+
"label": "Run reports",
|
|
150
|
+
"description": "Run the reports added to this connection, filtered by their prompts.",
|
|
151
|
+
"scopes": [],
|
|
152
|
+
"permissions": [
|
|
153
|
+
"Each report shared with the integration system user, and View on the domains securing its data"
|
|
154
|
+
],
|
|
155
|
+
"forbidden": "Share the report with the integration system user, enable it as a web service, and give its security group View on the domains securing the report's data.",
|
|
156
|
+
"tools": ["workday_list_reports", "workday_run_report"]
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
"limits": [
|
|
160
|
+
{
|
|
161
|
+
"id": "organizations",
|
|
162
|
+
"label": "Organizations",
|
|
163
|
+
"help": "Workday IDs of supervisory organizations (their sub-organizations included) or companies. The agent reaches only workers in them. Find an ID on the organization: Related Actions > Integration IDs > View Reference IDs (the Workday ID). Leave empty to allow every worker the account can see.",
|
|
164
|
+
"kind": "list",
|
|
165
|
+
"required": false,
|
|
166
|
+
"pattern": "^[0-9a-f]{32}$"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"id": "reports",
|
|
170
|
+
"label": "Reports",
|
|
171
|
+
"help": "Leave empty to allow every report added to this connection.",
|
|
172
|
+
"kind": "list",
|
|
173
|
+
"required": false,
|
|
174
|
+
"pattern": "^[A-Za-z0-9_.-]{1,200}$"
|
|
175
|
+
}
|
|
176
|
+
],
|
|
177
|
+
"verify": {
|
|
178
|
+
"label": "Workday tenant reached",
|
|
179
|
+
"check": "tenant"
|
|
180
|
+
},
|
|
181
|
+
"discover": {
|
|
182
|
+
"label": "Reports agents can run",
|
|
183
|
+
"check": "reports"
|
|
184
|
+
},
|
|
185
|
+
"revoke": "In Workday, open View API Clients, then API Clients for Integrations, then {brand.microsoft.appName}, and revoke its refresh token under Manage Refresh Tokens for Integrations, or inactivate the integration system user."
|
|
186
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../connectors/workday/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,eAAe;IACb,EAAE,EAAE,SAAS;IACb,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;CACzC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type ToolContext, type Toolset } from "../../packages/connector-kit/src/common.js";
|
|
2
|
+
type Mark = (status: number) => void;
|
|
3
|
+
export declare function workdayError(res: {
|
|
4
|
+
status: number;
|
|
5
|
+
data: unknown;
|
|
6
|
+
}): string;
|
|
7
|
+
export declare function worker(w: any): {
|
|
8
|
+
is_manager?: any;
|
|
9
|
+
id: any;
|
|
10
|
+
name: any;
|
|
11
|
+
worker_id: any;
|
|
12
|
+
title: any;
|
|
13
|
+
job_profile: any;
|
|
14
|
+
organization: {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string | null;
|
|
17
|
+
} | null;
|
|
18
|
+
location: any;
|
|
19
|
+
worker_type: any;
|
|
20
|
+
email: any;
|
|
21
|
+
};
|
|
22
|
+
export declare function scope(ctx: ToolContext, mark: Mark): {
|
|
23
|
+
limited: boolean;
|
|
24
|
+
org: (id: string | undefined) => Promise<boolean>;
|
|
25
|
+
worker: (w: any) => Promise<boolean>;
|
|
26
|
+
read: (id: string) => Promise<any>;
|
|
27
|
+
chart: (id: string) => Promise<any>;
|
|
28
|
+
};
|
|
29
|
+
export declare const workdayTools: Toolset;
|
|
30
|
+
export declare function trimRow(row: Record<string, unknown>): {
|
|
31
|
+
[k: string]: string | number | boolean | null;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { connectedReports } from "./vendor.js";
|
|
3
|
+
import { audited, Denied, json, listLimit, VendorFailed, } from "../../packages/connector-kit/src/common.js";
|
|
4
|
+
// Workday REST (staffing v7, common v1, absenceManagement v5) and custom reports. Paths are
|
|
5
|
+
// Workday's REST directory; answer fields follow CData's tables generated from Workday's specs
|
|
6
|
+
// (Workers, WorkersDirectReports, WorkersOrganizations, SupervisoryOrganizations,
|
|
7
|
+
// SupervisoryOrganizationsOrgChart, Balances, WorkersTimeOffDetails,
|
|
8
|
+
// WorkersEligibleAbsenceTypes, WorkersRequestTimeOff; read October 27, 2026).
|
|
9
|
+
const WID = /^[0-9a-f]{32}$/;
|
|
10
|
+
const DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
11
|
+
// Workday's submit action for a business process (CData's WorkersRequestTimeOff).
|
|
12
|
+
const SUBMIT = "d9e4223e446c11de98360015c5e6daf6";
|
|
13
|
+
// Supervisory levels walked up for a management chain or an organization limit.
|
|
14
|
+
const MAX_LEVELS = 12;
|
|
15
|
+
const MAX_ROWS = 200;
|
|
16
|
+
const OUTSIDE = "This agent may not look up that worker";
|
|
17
|
+
const api = (ctx, service, rest) => `/ccx/api/${service}/${ctx.config.tenant}${rest}`;
|
|
18
|
+
export function workdayError(res) {
|
|
19
|
+
const d = res.data;
|
|
20
|
+
const detail = typeof d === "string"
|
|
21
|
+
? d.slice(0, 200)
|
|
22
|
+
: [d?.error, ...(Array.isArray(d?.errors) ? d.errors.map((e) => e?.error) : [])]
|
|
23
|
+
.filter((e) => typeof e === "string")
|
|
24
|
+
.join("; ")
|
|
25
|
+
.slice(0, 500);
|
|
26
|
+
return `Workday answered ${res.status}${detail ? `: ${detail}` : ""}`;
|
|
27
|
+
}
|
|
28
|
+
async function ok(ctx, mark, path, body, hintTool) {
|
|
29
|
+
const res = await ctx.call(body === undefined ? { method: "GET", path } : { method: "POST", path, body });
|
|
30
|
+
mark(res.status);
|
|
31
|
+
if (res.status < 200 || res.status >= 300)
|
|
32
|
+
throw new VendorFailed(res.status, workdayError(res), hintTool);
|
|
33
|
+
return res.data;
|
|
34
|
+
}
|
|
35
|
+
const ref = (r) => (r?.id ? { id: r.id, name: r.descriptor ?? null } : null);
|
|
36
|
+
// Staffing's worker (primaryJob, person) and common's summary (direct reports) share these.
|
|
37
|
+
export function worker(w) {
|
|
38
|
+
return {
|
|
39
|
+
id: w.id,
|
|
40
|
+
name: w.descriptor ?? null,
|
|
41
|
+
worker_id: w.workerId ?? null,
|
|
42
|
+
title: w.primaryJob?.businessTitle ?? w.businessTitle ?? null,
|
|
43
|
+
job_profile: w.primaryJob?.jobProfile?.descriptor ?? null,
|
|
44
|
+
organization: ref(w.primaryJob?.supervisoryOrganization ?? w.primarySupervisoryOrganization),
|
|
45
|
+
location: w.primaryJob?.location?.descriptor ?? null,
|
|
46
|
+
worker_type: w.workerType?.descriptor ?? null,
|
|
47
|
+
email: w.person?.email ?? w.primaryWorkEmail ?? null,
|
|
48
|
+
...(typeof w.isManager === "boolean" ? { is_manager: w.isManager } : {}),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const page = (data, offset, limit) => {
|
|
52
|
+
const total = typeof data?.total === "number" ? data.total : 0;
|
|
53
|
+
return offset + limit < total ? String(offset + limit) : null;
|
|
54
|
+
};
|
|
55
|
+
const offsetOf = (cursor) => {
|
|
56
|
+
if (cursor === undefined)
|
|
57
|
+
return 0;
|
|
58
|
+
if (!/^\d{1,6}$/.test(cursor))
|
|
59
|
+
throw new Denied("Pass back the cursor a listing returned");
|
|
60
|
+
return Number(cursor);
|
|
61
|
+
};
|
|
62
|
+
// The key's organizations limit: Workday IDs of supervisory organizations (their
|
|
63
|
+
// sub-organizations included) or of any other organization a worker belongs to, e.g. a company.
|
|
64
|
+
// Memoized per call.
|
|
65
|
+
export function scope(ctx, mark) {
|
|
66
|
+
const limit = listLimit(ctx.limits, "organizations");
|
|
67
|
+
const charts = new Map();
|
|
68
|
+
// Staffing's org chart of a supervisory organization: its superior and subordinates. null
|
|
69
|
+
// when the id is not a supervisory organization.
|
|
70
|
+
const chart = (id) => {
|
|
71
|
+
if (!charts.has(id))
|
|
72
|
+
charts.set(id, (async () => {
|
|
73
|
+
const res = await ctx.call({
|
|
74
|
+
method: "GET",
|
|
75
|
+
path: api(ctx, "staffing/v7", `/supervisoryOrganizations/${id}/orgChart`),
|
|
76
|
+
});
|
|
77
|
+
mark(res.status);
|
|
78
|
+
if (res.status === 400 || res.status === 404)
|
|
79
|
+
return null;
|
|
80
|
+
if (res.status < 200 || res.status >= 300)
|
|
81
|
+
throw new VendorFailed(res.status, workdayError(res));
|
|
82
|
+
return res.data?.data?.[0] ?? null;
|
|
83
|
+
})());
|
|
84
|
+
return charts.get(id);
|
|
85
|
+
};
|
|
86
|
+
async function org(id) {
|
|
87
|
+
if (!limit)
|
|
88
|
+
return true;
|
|
89
|
+
for (let level = 0; id && WID.test(id) && level < MAX_LEVELS; level++) {
|
|
90
|
+
if (limit.includes(id))
|
|
91
|
+
return true;
|
|
92
|
+
id = (await chart(id))?.superior?.id;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
async function worker(w) {
|
|
97
|
+
if (!limit)
|
|
98
|
+
return true;
|
|
99
|
+
const supervisory = (w.primaryJob?.supervisoryOrganization ?? w.primarySupervisoryOrganization)
|
|
100
|
+
?.id;
|
|
101
|
+
if (await org(supervisory))
|
|
102
|
+
return true;
|
|
103
|
+
const orgs = await ok(ctx, mark, api(ctx, "common/v1", `/workers/${w.id}/organizations?limit=100`));
|
|
104
|
+
return (orgs?.data ?? []).some((o) => o?.id && limit.includes(o.id));
|
|
105
|
+
}
|
|
106
|
+
// A worker read by id, refused (as if not found) when outside the key's organizations. It is
|
|
107
|
+
// the worker lookup capability's permission, whichever tool reads.
|
|
108
|
+
async function read(id) {
|
|
109
|
+
if (!WID.test(id))
|
|
110
|
+
throw new Denied("Give a worker's Workday ID (32 letters and digits)");
|
|
111
|
+
const res = await ctx.call({ method: "GET", path: api(ctx, "staffing/v7", `/workers/${id}`) });
|
|
112
|
+
mark(res.status);
|
|
113
|
+
if (limit && res.status === 404)
|
|
114
|
+
throw new Denied(OUTSIDE);
|
|
115
|
+
if (res.status < 200 || res.status >= 300)
|
|
116
|
+
throw new VendorFailed(res.status, workdayError(res), "workday_get_worker");
|
|
117
|
+
if (!(await worker(res.data)))
|
|
118
|
+
throw new Denied(OUTSIDE);
|
|
119
|
+
return res.data;
|
|
120
|
+
}
|
|
121
|
+
return { limited: limit !== null, org, worker, read, chart };
|
|
122
|
+
}
|
|
123
|
+
const wid = (what) => z.string().describe(`The ${what}'s Workday ID (32 letters and digits).`);
|
|
124
|
+
const cursor = z.string().optional().describe("The `next` value of the previous page.");
|
|
125
|
+
export const workdayTools = {
|
|
126
|
+
names: [
|
|
127
|
+
"workday_search_workers",
|
|
128
|
+
"workday_get_worker",
|
|
129
|
+
"workday_list_direct_reports",
|
|
130
|
+
"workday_get_management_chain",
|
|
131
|
+
"workday_get_organization",
|
|
132
|
+
"workday_list_organization_workers",
|
|
133
|
+
"workday_get_time_off_balances",
|
|
134
|
+
"workday_list_time_off",
|
|
135
|
+
"workday_list_time_off_types",
|
|
136
|
+
"workday_request_time_off",
|
|
137
|
+
"workday_list_reports",
|
|
138
|
+
"workday_run_report",
|
|
139
|
+
],
|
|
140
|
+
register(server, ctx, allowed) {
|
|
141
|
+
const readOnly = { readOnlyHint: true, openWorldHint: true };
|
|
142
|
+
const tool = (name, description, inputSchema, target, run, annotations = readOnly) => {
|
|
143
|
+
if (allowed.has(name))
|
|
144
|
+
server.registerTool(name, { description, inputSchema, annotations }, (args) => audited(ctx, name, target(args), async (mark, retarget) => json(await run(args, mark, retarget))));
|
|
145
|
+
};
|
|
146
|
+
tool("workday_search_workers", "Find workers by name or worker ID (Workday's search: case-insensitive, space-separated words match any). Returns name, title, organization, location and work email; never pay or personal data.", z.object({
|
|
147
|
+
query: z.string().min(1).max(100),
|
|
148
|
+
max_results: z.number().int().min(1).max(50).default(10),
|
|
149
|
+
cursor,
|
|
150
|
+
}), (a) => a.query, async ({ query, max_results, cursor: c }, mark) => {
|
|
151
|
+
const offset = offsetOf(c);
|
|
152
|
+
const s = scope(ctx, mark);
|
|
153
|
+
const q = new URLSearchParams({
|
|
154
|
+
search: query,
|
|
155
|
+
limit: String(max_results),
|
|
156
|
+
offset: String(offset),
|
|
157
|
+
});
|
|
158
|
+
const data = await ok(ctx, mark, api(ctx, "staffing/v7", `/workers?${q}`));
|
|
159
|
+
const found = [];
|
|
160
|
+
for (const w of data?.data ?? [])
|
|
161
|
+
if (await s.worker(w))
|
|
162
|
+
found.push(worker(w));
|
|
163
|
+
return { workers: found, next: page(data, offset, max_results) };
|
|
164
|
+
});
|
|
165
|
+
tool("workday_get_worker", "Read one worker: name, worker ID, title, job profile, supervisory organization, location, worker type and work email.", z.object({ worker_id: wid("worker") }), (a) => a.worker_id, async ({ worker_id }, mark) => worker(await scope(ctx, mark).read(worker_id)));
|
|
166
|
+
tool("workday_list_direct_reports", "List a worker's direct reports.", z.object({ worker_id: wid("manager"), cursor }), (a) => a.worker_id, async ({ worker_id, cursor: c }, mark) => {
|
|
167
|
+
const offset = offsetOf(c);
|
|
168
|
+
const s = scope(ctx, mark);
|
|
169
|
+
await s.read(worker_id);
|
|
170
|
+
const data = await ok(ctx, mark, api(ctx, "common/v1", `/workers/${worker_id}/directReports?limit=100&offset=${offset}`));
|
|
171
|
+
const reports = [];
|
|
172
|
+
for (const w of data?.data ?? [])
|
|
173
|
+
if (await s.worker(w))
|
|
174
|
+
reports.push(worker(w));
|
|
175
|
+
return { direct_reports: reports, next: page(data, offset, 100) };
|
|
176
|
+
});
|
|
177
|
+
tool("workday_get_management_chain", "A worker's managers, nearest first, up the supervisory organizations. Stops at the top, or where this agent's organizations end.", z.object({ worker_id: wid("worker") }), (a) => a.worker_id, async ({ worker_id }, mark) => {
|
|
178
|
+
const s = scope(ctx, mark);
|
|
179
|
+
const w = await s.read(worker_id);
|
|
180
|
+
const chain = [];
|
|
181
|
+
let orgId = w.primaryJob?.supervisoryOrganization?.id;
|
|
182
|
+
for (let level = 0; orgId && WID.test(orgId) && level < MAX_LEVELS; level++) {
|
|
183
|
+
if (!(await s.org(orgId)))
|
|
184
|
+
break;
|
|
185
|
+
const o = await ok(ctx, mark, api(ctx, "staffing/v7", `/supervisoryOrganizations/${orgId}`));
|
|
186
|
+
const m = o?.manager;
|
|
187
|
+
const last = chain.length ? chain[chain.length - 1].id : worker_id;
|
|
188
|
+
if (m?.id && m.id !== last)
|
|
189
|
+
chain.push({ id: m.id, name: m.descriptor ?? null, organization: ref(o) });
|
|
190
|
+
orgId = (await s.chart(orgId))?.superior?.id;
|
|
191
|
+
}
|
|
192
|
+
return { worker: ref(w), managers: chain };
|
|
193
|
+
});
|
|
194
|
+
tool("workday_get_organization", "Read a supervisory organization: its name, code, manager, superior organization and sub-organizations.", z.object({ org_id: wid("supervisory organization") }), (a) => a.org_id, async ({ org_id }, mark) => {
|
|
195
|
+
if (!WID.test(org_id))
|
|
196
|
+
throw new Denied("Give an organization's Workday ID");
|
|
197
|
+
const s = scope(ctx, mark);
|
|
198
|
+
if (!(await s.org(org_id)))
|
|
199
|
+
throw new Denied("This agent may not look up that organization");
|
|
200
|
+
const o = await ok(ctx, mark, api(ctx, "staffing/v7", `/supervisoryOrganizations/${org_id}`));
|
|
201
|
+
const c = await s.chart(org_id);
|
|
202
|
+
const superior = c?.superior?.id && (await s.org(c.superior.id)) ? ref(c.superior) : null;
|
|
203
|
+
return {
|
|
204
|
+
id: o.id,
|
|
205
|
+
name: o.name ?? o.descriptor ?? null,
|
|
206
|
+
code: o.code ?? null,
|
|
207
|
+
manager: ref(o.manager),
|
|
208
|
+
superior,
|
|
209
|
+
sub_organizations: (c?.subordinates ?? []).map((x) => ({
|
|
210
|
+
id: x.id,
|
|
211
|
+
name: x.name ?? x.descriptor ?? null,
|
|
212
|
+
code: x.code ?? null,
|
|
213
|
+
inactive: x.inactive ?? false,
|
|
214
|
+
managers: (x.managers ?? []).map(ref).filter(Boolean),
|
|
215
|
+
})),
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
tool("workday_list_organization_workers", "List the workers in a supervisory organization.", z.object({ org_id: wid("supervisory organization"), cursor }), (a) => a.org_id, async ({ org_id, cursor: c }, mark) => {
|
|
219
|
+
if (!WID.test(org_id))
|
|
220
|
+
throw new Denied("Give an organization's Workday ID");
|
|
221
|
+
const offset = offsetOf(c);
|
|
222
|
+
if (!(await scope(ctx, mark).org(org_id)))
|
|
223
|
+
throw new Denied("This agent may not look up that organization");
|
|
224
|
+
const data = await ok(ctx, mark, api(ctx, "common/v1", `/supervisoryOrganizations/${org_id}/workers?limit=100&offset=${offset}`));
|
|
225
|
+
return { workers: (data?.data ?? []).map(worker), next: page(data, offset, 100) };
|
|
226
|
+
});
|
|
227
|
+
tool("workday_get_time_off_balances", "A worker's time off and leave balances, per plan, as of today or a given date.", z.object({
|
|
228
|
+
worker_id: wid("worker"),
|
|
229
|
+
as_of: z.string().optional().describe("YYYY-MM-DD; today when left out."),
|
|
230
|
+
}), (a) => a.worker_id, async ({ worker_id, as_of }, mark) => {
|
|
231
|
+
if (as_of !== undefined && !DATE.test(as_of))
|
|
232
|
+
throw new Denied("Give as_of as YYYY-MM-DD");
|
|
233
|
+
await scope(ctx, mark).read(worker_id);
|
|
234
|
+
const q = new URLSearchParams({
|
|
235
|
+
worker: worker_id,
|
|
236
|
+
limit: "100",
|
|
237
|
+
...(as_of ? { effective: as_of } : {}),
|
|
238
|
+
});
|
|
239
|
+
const data = await ok(ctx, mark, api(ctx, "absenceManagement/v5", `/balances?${q}`));
|
|
240
|
+
const rows = (data?.data ?? []);
|
|
241
|
+
// The filter is Workday's; an answer about anyone else is never passed on.
|
|
242
|
+
if (rows.some((b) => b?.worker?.id !== worker_id))
|
|
243
|
+
throw new Denied("Workday answered with another worker's balances");
|
|
244
|
+
return {
|
|
245
|
+
balances: rows.map((b) => ({
|
|
246
|
+
plan: b.absencePlan?.descriptor ?? null,
|
|
247
|
+
category: b.category?.descriptor ?? null,
|
|
248
|
+
balance: b.quantity ?? null,
|
|
249
|
+
unit: b.unit?.descriptor ?? null,
|
|
250
|
+
as_of: b.effectiveDate ?? null,
|
|
251
|
+
})),
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
tool("workday_list_time_off", "A worker's time off entries (requested, approved and taken) between two dates, at most a year apart.", z.object({
|
|
255
|
+
worker_id: wid("worker"),
|
|
256
|
+
from: z.string().describe("YYYY-MM-DD"),
|
|
257
|
+
to: z.string().describe("YYYY-MM-DD"),
|
|
258
|
+
cursor,
|
|
259
|
+
}), (a) => `${a.worker_id} ${a.from}..${a.to}`, async ({ worker_id, from, to, cursor: c }, mark) => {
|
|
260
|
+
if (!DATE.test(from) || !DATE.test(to))
|
|
261
|
+
throw new Denied("Give from and to as YYYY-MM-DD");
|
|
262
|
+
const days = (Date.parse(to) - Date.parse(from)) / 86_400_000;
|
|
263
|
+
if (!(days >= 0 && days <= 366))
|
|
264
|
+
throw new Denied("from must be before to, at most a year apart");
|
|
265
|
+
const offset = offsetOf(c);
|
|
266
|
+
await scope(ctx, mark).read(worker_id);
|
|
267
|
+
const q = new URLSearchParams({
|
|
268
|
+
fromDate: from,
|
|
269
|
+
toDate: to,
|
|
270
|
+
limit: "100",
|
|
271
|
+
offset: String(offset),
|
|
272
|
+
});
|
|
273
|
+
const data = await ok(ctx, mark, api(ctx, "absenceManagement/v5", `/workers/${worker_id}/timeOffDetails?${q}`));
|
|
274
|
+
return {
|
|
275
|
+
entries: (data?.data ?? []).map((e) => ({
|
|
276
|
+
date: e.date ?? null,
|
|
277
|
+
type: e.timeOffType?.descriptor ?? null,
|
|
278
|
+
quantity: e.quantity ?? null,
|
|
279
|
+
unit: e.unit?.descriptor ?? null,
|
|
280
|
+
status: e.status?.descriptor ?? null,
|
|
281
|
+
comment: e.comment ?? null,
|
|
282
|
+
})),
|
|
283
|
+
next: page(data, offset, 100),
|
|
284
|
+
};
|
|
285
|
+
});
|
|
286
|
+
tool("workday_list_time_off_types", "The time off types a worker may request, with their ids for workday_request_time_off, unit and default daily quantity.", z.object({ worker_id: wid("worker") }), (a) => a.worker_id, async ({ worker_id }, mark) => {
|
|
287
|
+
await scope(ctx, mark).read(worker_id);
|
|
288
|
+
const data = await ok(ctx, mark, api(ctx, "absenceManagement/v5", `/workers/${worker_id}/eligibleAbsenceTypes?limit=100`));
|
|
289
|
+
return {
|
|
290
|
+
types: (data?.data ?? []).map((t) => ({
|
|
291
|
+
id: t.id,
|
|
292
|
+
name: t.descriptor ?? null,
|
|
293
|
+
group: t.absenceTypeGroup?.descriptor ?? null,
|
|
294
|
+
unit: t.unitOfTime?.descriptor ?? null,
|
|
295
|
+
daily_default: t.dailyDefaultQuantity ?? null,
|
|
296
|
+
reason_required: t.reasonRequired ?? false,
|
|
297
|
+
start_and_end_time_required: t.startAndEndTimeRequired ?? false,
|
|
298
|
+
})),
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
tool("workday_request_time_off", "Submit a time off request for a worker. It starts Workday's Request Time Off approval, as the worker's request; the worker and their manager are notified as Workday is set up to do. Get type ids from workday_list_time_off_types.", z.object({
|
|
302
|
+
worker_id: wid("worker"),
|
|
303
|
+
days: z
|
|
304
|
+
.array(z.object({
|
|
305
|
+
date: z.string().describe("YYYY-MM-DD"),
|
|
306
|
+
time_off_type_id: z.string(),
|
|
307
|
+
quantity: z
|
|
308
|
+
.number()
|
|
309
|
+
.positive()
|
|
310
|
+
.max(24)
|
|
311
|
+
.describe("Hours or days, in the type's unit."),
|
|
312
|
+
comment: z.string().max(500).optional(),
|
|
313
|
+
}))
|
|
314
|
+
.min(1)
|
|
315
|
+
.max(31),
|
|
316
|
+
comment: z.string().max(1000).optional().describe("A comment on the whole request."),
|
|
317
|
+
}), (a) => a.worker_id, async ({ worker_id, days, comment }, mark, retarget) => {
|
|
318
|
+
for (const d of days) {
|
|
319
|
+
if (!DATE.test(d.date))
|
|
320
|
+
throw new Denied("Give each date as YYYY-MM-DD");
|
|
321
|
+
if (!WID.test(d.time_off_type_id))
|
|
322
|
+
throw new Denied("Give a time off type id from workday_list_time_off_types");
|
|
323
|
+
}
|
|
324
|
+
await scope(ctx, mark).read(worker_id);
|
|
325
|
+
retarget(`${worker_id} ${days.map((d) => d.date).join(",")}`.slice(0, 300));
|
|
326
|
+
const data = await ok(ctx, mark, api(ctx, "absenceManagement/v5", `/workers/${worker_id}/requestTimeOff`), {
|
|
327
|
+
businessProcessParameters: {
|
|
328
|
+
action: { id: SUBMIT },
|
|
329
|
+
...(comment ? { comment } : {}),
|
|
330
|
+
},
|
|
331
|
+
days: days.map((d) => ({
|
|
332
|
+
date: d.date,
|
|
333
|
+
dailyQuantity: d.quantity,
|
|
334
|
+
timeOffType: { id: d.time_off_type_id },
|
|
335
|
+
...(d.comment ? { comment: d.comment } : {}),
|
|
336
|
+
})),
|
|
337
|
+
});
|
|
338
|
+
const bp = data?.businessProcessParameters;
|
|
339
|
+
return {
|
|
340
|
+
submitted: true,
|
|
341
|
+
status: bp?.overallStatus ?? bp?.transactionStatus?.descriptor ?? null,
|
|
342
|
+
process: ref(bp?.overallBusinessProcess),
|
|
343
|
+
days: days.length,
|
|
344
|
+
};
|
|
345
|
+
}, { readOnlyHint: false, destructiveHint: false, openWorldHint: true });
|
|
346
|
+
const reports = () => {
|
|
347
|
+
const limit = listLimit(ctx.limits, "reports");
|
|
348
|
+
return connectedReports(ctx.config).filter((r) => !limit || limit.includes(r.name));
|
|
349
|
+
};
|
|
350
|
+
tool("workday_list_reports", "The Workday reports this agent may run, with each report's prompts (filters) and their types.", z.object({}), () => null, async () => ({
|
|
351
|
+
reports: reports().map((r) => ({ report: r.name, prompts: r.prompts })),
|
|
352
|
+
}));
|
|
353
|
+
tool("workday_run_report", "Run one of the Workday reports from workday_list_reports, with values for any of its prompts (dates as YYYY-MM-DD). Returns its rows, at most max_rows.", z.object({
|
|
354
|
+
report: z.string(),
|
|
355
|
+
prompts: z.record(z.string(), z.string().max(200)).default({}),
|
|
356
|
+
max_rows: z.number().int().min(1).max(MAX_ROWS).default(50),
|
|
357
|
+
}), (a) => a.report, async ({ report, prompts, max_rows }, mark, retarget) => {
|
|
358
|
+
const r = reports().find((x) => x.name === report);
|
|
359
|
+
if (!r)
|
|
360
|
+
throw new Denied(`${report} is not a report this agent may run`);
|
|
361
|
+
const q = new URLSearchParams();
|
|
362
|
+
for (const [name, value] of Object.entries(prompts)) {
|
|
363
|
+
const p = r.prompts.find((x) => x.name === name);
|
|
364
|
+
if (!p)
|
|
365
|
+
throw new Denied(`${report} has no prompt ${name}. Its prompts: ${r.prompts.map((x) => x.name).join(", ") || "none"}`);
|
|
366
|
+
if (p.type === "date" && !DATE.test(value))
|
|
367
|
+
throw new Denied(`Give ${name} as YYYY-MM-DD`);
|
|
368
|
+
q.append(name, value);
|
|
369
|
+
}
|
|
370
|
+
q.set("format", "json");
|
|
371
|
+
const s = scope(ctx, mark);
|
|
372
|
+
const column = ctx.config.reportOrgColumn;
|
|
373
|
+
if (s.limited && !column)
|
|
374
|
+
throw new Denied("This agent is limited to some organizations, and reports have no organization column set, so it may not run reports");
|
|
375
|
+
retarget(`${report}?${q}`.slice(0, 300));
|
|
376
|
+
const enc = encodeURIComponent;
|
|
377
|
+
const data = await ok(ctx, mark, `/ccx/service/customreport2/${ctx.config.tenant}/${enc(r.owner)}/${enc(r.report)}?${q}`);
|
|
378
|
+
if (!Array.isArray(data?.Report_Entry))
|
|
379
|
+
throw new VendorFailed(200, "Workday's answer was not a JSON report");
|
|
380
|
+
const rows = [];
|
|
381
|
+
for (const row of data.Report_Entry) {
|
|
382
|
+
if (s.limited) {
|
|
383
|
+
const v = row[column];
|
|
384
|
+
const ids = (Array.isArray(v) ? v : [v]).filter((x) => typeof x === "string");
|
|
385
|
+
let inside = false;
|
|
386
|
+
for (const id of ids)
|
|
387
|
+
if ((inside = await s.org(id)))
|
|
388
|
+
break;
|
|
389
|
+
if (!inside)
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
rows.push(trimRow(row));
|
|
393
|
+
if (rows.length === max_rows)
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
return { report, rows, truncated: rows.length === max_rows };
|
|
397
|
+
});
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
export function trimRow(row) {
|
|
401
|
+
return Object.fromEntries(Object.entries(row).map(([k, v]) => [
|
|
402
|
+
k,
|
|
403
|
+
typeof v === "string"
|
|
404
|
+
? v.slice(0, 500)
|
|
405
|
+
: typeof v === "number" || typeof v === "boolean" || v === null
|
|
406
|
+
? v
|
|
407
|
+
: JSON.stringify(v).slice(0, 500),
|
|
408
|
+
]));
|
|
409
|
+
}
|
|
410
|
+
//# sourceMappingURL=tools.js.map
|