Skip to content

Commit 569affb

Browse files
committed
fix: improve ai tools
1 parent c37cb15 commit 569affb

File tree

2 files changed

+94
-101
lines changed

2 files changed

+94
-101
lines changed

packages/ai/src/plugin.ts

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ export class AiPlugin extends RuntimePlugin<AiPluginOptions> {
203203
Keep the response short and concise, and only use tools when necessary. Keep the response length under 2000 characters.
204204
Do not include your own text in the response unless necessary. For text formatting, you can use discord's markdown syntax.
205205
${message.inGuild() ? `\nYou are currently in a guild named ${message.guild.name} whose id is ${message.guildId}. While in guild, you can fetch member information if needed.` : '\nYou are currently in a direct message with the user.'}
206-
If the user asks you to create a poll or embeds, create a text containing the poll or embed information. If structured response is possible, use the structured response format.
206+
If the user asks you to create a poll or embeds, create a text containing the poll or embed information as a markdown instead of json. If structured response is possible, use the structured response format instead.
207207
If the user asks you to perform a task that requires a tool, use the tool to perform the task and return the result.
208208
`;
209209

@@ -267,7 +267,7 @@ export class AiPlugin extends RuntimePlugin<AiPluginOptions> {
267267
const r2 = await call({
268268
includeTools: false,
269269
disableObjectMode: false,
270-
prompt: `Original context: ${r1.text} ${r1.text}\n\nGenerate a structured response based on the previous response`,
270+
prompt: `Original context: ${originalPrompt} ${r1.text}\n\nGenerate a structured response based on the previous response`,
271271
});
272272

273273
result = r2;
@@ -288,32 +288,36 @@ export class AiPlugin extends RuntimePlugin<AiPluginOptions> {
288288
} catch {}
289289

290290
if (structuredResult) {
291-
const { poll, content, embeds } = structuredResult;
291+
const { poll, content, embed } = structuredResult;
292292

293-
if (!poll && !content && !embeds) {
293+
if (!poll && !content && !embed) {
294294
Logger.warn(
295-
'AI response did not include any content, embeds, or poll.',
295+
'AI response did not include any content, embed, or poll.',
296296
);
297297
return;
298298
}
299299

300300
await message.reply({
301301
content: content?.substring(0, 2000),
302-
embeds: embeds?.map((embed) => ({
303-
title: embed.title,
304-
description: embed.description,
305-
url: embed.url,
306-
color: embed.color,
307-
image: embed.image?.url ? { url: embed.image.url } : undefined,
308-
thumbnail: embed.thumbnail?.url
309-
? { url: embed.thumbnail.url }
310-
: undefined,
311-
fields: embed.fields?.map((field) => ({
312-
name: field.name,
313-
value: field.value,
314-
inline: field.inline,
315-
})),
316-
})),
302+
embeds: embed
303+
? [
304+
{
305+
title: embed.title,
306+
description: embed.description,
307+
url: embed.url,
308+
color: embed.color,
309+
image: embed.image ? { url: embed.image } : undefined,
310+
thumbnail: embed.thumbnailImage
311+
? { url: embed.thumbnailImage }
312+
: undefined,
313+
fields: embed.fields?.map((field) => ({
314+
name: field.name,
315+
value: field.value,
316+
inline: field.inline,
317+
})),
318+
},
319+
]
320+
: [],
317321
poll: poll
318322
? {
319323
allowMultiselect: poll.allow_multiselect,

packages/ai/src/schema.ts

Lines changed: 70 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -22,90 +22,79 @@ export const AiResponseSchema = z
2222
.describe(
2323
'The content of the message. This can be plain text or markdown. This is an optional field.',
2424
),
25-
embeds: z
26-
.array(
27-
z.object({
28-
title: z
29-
.string()
30-
.trim()
31-
.optional()
32-
.describe('The title of the embed. This is an optional field.'),
33-
description: z
34-
.string()
35-
.trim()
36-
.optional()
37-
.describe(
38-
'The description of the embed. This is an optional field.',
39-
),
40-
url: z
41-
.string()
42-
.optional()
43-
.describe(
44-
'The URL of the embed. No need to specify this if it is not needed. It is not a required field.',
45-
),
46-
color: z
47-
.number()
48-
.int()
49-
.min(0)
50-
.max(16777215)
51-
.optional()
52-
.describe(
53-
'The color of the embed in RGB format. This is an optional field.',
54-
),
55-
image: z
56-
.object({
57-
url: z
58-
.string()
59-
.optional()
60-
.describe(
61-
'The URL of the image in the embed. This is an optional field.',
62-
),
63-
})
64-
.optional(),
65-
thumbnail: z
66-
.object({
67-
url: z
68-
.string()
25+
embed: z
26+
.object({
27+
title: z
28+
.string()
29+
.trim()
30+
.optional()
31+
.describe('The title of the embed. This is an optional field.'),
32+
description: z
33+
.string()
34+
.trim()
35+
.optional()
36+
.describe('The description of the embed. This is an optional field.'),
37+
url: z
38+
.string()
39+
.optional()
40+
.describe(
41+
'A URL associated with the embed. This is an optional field.',
42+
),
43+
color: z
44+
.number()
45+
.int()
46+
.min(0)
47+
.max(16777215)
48+
.optional()
49+
.describe(
50+
'A color for the embed, represented as an integer in RGB format. This is an optional field.',
51+
),
52+
thumbnailImage: z
53+
.string()
54+
.optional()
55+
.describe('A URL for a thumbnail image. This is an optional field.'),
56+
image: z
57+
.string()
58+
.optional()
59+
.describe(
60+
'A URL for a main image in the embed. This is an optional field.',
61+
),
62+
footer: z
63+
.string()
64+
.optional()
65+
.describe('The footer text of the embed. This is an optional field.'),
66+
footerIcon: z
67+
.string()
68+
.optional()
69+
.describe(
70+
'A URL for an icon to display in the footer of the embed. This is an optional field.',
71+
),
72+
fields: z
73+
.array(
74+
z.object({
75+
name: z.string().trim().describe('The name of the field.'),
76+
value: z.string().trim().describe('The value of the field.'),
77+
inline: z
78+
.boolean()
6979
.optional()
80+
.default(false)
7081
.describe(
71-
'The URL of the thumbnail in the embed. This is an optional field.',
82+
'Whether the field should be displayed inline with other fields. This is an optional field which defaults to false.',
7283
),
73-
})
74-
.optional(),
75-
fields: z
76-
.array(
77-
z.object({
78-
name: z
79-
.string()
80-
.trim()
81-
.describe(
82-
'The name of the field. This is an optional field.',
83-
),
84-
value: z
85-
.string()
86-
.trim()
87-
.describe(
88-
'The value of the field. This is an optional field.',
89-
),
90-
inline: z
91-
.boolean()
92-
.optional()
93-
.default(false)
94-
.describe(
95-
'Whether the field is inline. This is an optional field. It defaults to false.',
96-
),
97-
}),
98-
)
99-
.max(25)
100-
.min(0)
101-
.optional()
102-
.describe('An array of fields in the embed'),
103-
}),
104-
)
105-
.max(10)
106-
.min(0)
84+
}),
85+
)
86+
.min(0)
87+
.max(25)
88+
.default([])
89+
.optional()
90+
.describe(
91+
'An array of fields to include in the embed. Each field should be an object with "name" and "value" properties. This is an optional field.',
92+
),
93+
})
10794
.optional()
108-
.describe('An array of embeds to include in the message'),
95+
.describe(
96+
'An object representing embeds to include in the discord message. This is an optional field.',
97+
),
10998
poll: z
11099
.object({
111100
question: pollMediaObject,
@@ -132,5 +121,5 @@ export const AiResponseSchema = z
132121
.describe('An object representing a poll to include in the message'),
133122
})
134123
.describe(
135-
'The schema for an AI response message, including content and embeds. At least one of content, embeds, or poll must be present.',
124+
'The schema for an AI response message to be sent to discord, including content and embeds. At least one of content, embeds, or poll must be present.',
136125
);

0 commit comments

Comments
 (0)