Skip to content

Commit def8c64

Browse files
committed
feat: make query to aibots
1 parent 28d862c commit def8c64

File tree

5 files changed

+165
-35
lines changed

5 files changed

+165
-35
lines changed

packages/backend/src/apps/aibots/actions/send-query.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { IDataOutMetadata, IExecutionStep } from '@plumber/types'
2+
import { dataOutSchema } from './schema'
3+
4+
async function getDataOutMetadata(
5+
step: IExecutionStep,
6+
): Promise<IDataOutMetadata> {
7+
const { dataOut: rawDataOut } = step
8+
9+
if (!rawDataOut) {
10+
return null
11+
}
12+
13+
dataOutSchema.parse(rawDataOut)
14+
15+
const metadata: IDataOutMetadata = {
16+
data: {
17+
response: {
18+
content: {
19+
label: 'Response',
20+
},
21+
},
22+
},
23+
}
24+
25+
// Recursively hide all fields except the ones explicitly defined in metadata
26+
function hideAllFields(obj: any, metadataPath: any = {}) {
27+
const result: any = { ...metadataPath }
28+
29+
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
30+
Object.entries(obj).forEach(([key, value]) => {
31+
// If this key is already defined in metadata, recurse into it
32+
if (metadataPath[key]) {
33+
result[key] = hideAllFields(value, metadataPath[key])
34+
} else {
35+
// Otherwise, hide this field
36+
result[key] = { isHidden: true }
37+
}
38+
})
39+
}
40+
41+
return result
42+
}
43+
44+
const finalMetadata = hideAllFields(rawDataOut.data, metadata.data)
45+
46+
return {
47+
data: finalMetadata,
48+
}
49+
}
50+
51+
export default getDataOutMetadata
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import HttpError from '@/errors/http'
2+
import StepError, { GenericSolution } from '@/errors/step'
3+
import { IRawAction } from '@plumber/types'
4+
import { ZodError } from 'zod'
5+
import { fromZodError } from 'zod-validation-error'
6+
import getDataOutMetadata from './get-data-out-metadata'
7+
import { parametersSchema } from './schema'
8+
9+
const action: IRawAction = {
10+
name: 'Send Query',
11+
key: 'sendQuery',
12+
description: 'Sends a query to your customised AI Bot',
13+
arguments: [
14+
{
15+
label: 'Bot API key',
16+
key: 'apiKey',
17+
description: 'Enter the API key for your bot',
18+
type: 'string' as const,
19+
required: true,
20+
variables: false,
21+
},
22+
{
23+
label: 'Query',
24+
key: 'query',
25+
type: 'string' as const,
26+
required: true,
27+
variables: true,
28+
},
29+
],
30+
31+
getDataOutMetadata,
32+
33+
async run($) {
34+
try {
35+
const parameters = parametersSchema.parse($.step.parameters)
36+
37+
const { query, apiKey } = parameters
38+
39+
const headers = { 'X-ATLAS-Key': apiKey }
40+
41+
// create a new chat
42+
const response = await $.http.post(
43+
`/chats`,
44+
{ name: 'Chat from Plumber' },
45+
{ headers },
46+
)
47+
48+
// /chats/:chatId/messages requires FormData
49+
const chatId = response.data.id
50+
const formData = new FormData()
51+
formData.append('content', query)
52+
53+
// send the query and get the response
54+
const chatResponse = await $.http.post(
55+
`/chats/:chatId/messages`,
56+
formData,
57+
{
58+
headers,
59+
urlPathParams: { chatId },
60+
},
61+
)
62+
63+
$.setActionItem({
64+
raw: {
65+
data: chatResponse.data,
66+
},
67+
})
68+
} catch (error) {
69+
// if the user enters an invalid API key, aibots will return a 401 error
70+
if (error instanceof HttpError && error.response.status === 401) {
71+
throw new StepError(
72+
'Invalid API key',
73+
'Please check that you have entered a valid API key',
74+
$.step.position,
75+
$.app.name,
76+
)
77+
}
78+
79+
if (error instanceof ZodError) {
80+
const firstError = fromZodError(error).details[0]
81+
82+
throw new StepError(
83+
`${firstError.message} under set up step`,
84+
GenericSolution.ReconfigureInvalidField,
85+
$.step.position,
86+
$.app.name,
87+
)
88+
}
89+
90+
throw error
91+
}
92+
},
93+
}
94+
95+
export default action
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { z } from 'zod'
2+
3+
export const parametersSchema = z.object({
4+
apiKey: z.string().min(1),
5+
query: z.string().min(1),
6+
})
7+
8+
export const dataOutSchema = z.object({
9+
data: z.object({
10+
response: z.object({
11+
content: z.string(),
12+
}),
13+
}),
14+
})

packages/backend/src/apps/aibots/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ const app: IApp = {
88
description: 'Integrate with your customised AI Bot',
99
iconUrl: '{BASE_URL}/apps/aibots/assets/favicon.svg',
1010
authDocUrl: '',
11-
baseUrl: '',
12-
apiBaseUrl: '',
11+
baseUrl: 'https://aibots.gov.sg',
12+
apiBaseUrl: 'https://api.uat.aibots.gov.sg/v1.0/api',
1313
primaryColor: '',
1414
category: 'ai',
1515
// TODO: add the actual auth here
16+
// there is currently no verification available for aibots
17+
// its done directly in the action itself
18+
// (as requested by AiBots team)
1619
// auth,
1720
actions,
1821
}

0 commit comments

Comments
 (0)