Skip to content

Commit 1c76f86

Browse files
authored
feat: add instruction mode and enable use of instruction details (#272)
feat(langs): add fr translation for prompts feat: add circular progress when changing step
1 parent 7401d1a commit 1c76f86

File tree

9 files changed

+174
-21
lines changed

9 files changed

+174
-21
lines changed

src/config/appSettingsType.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Member } from '@graasp/sdk';
22

3-
import { AssistantPersona } from '@/interfaces/assistant';
3+
import { AssistantPersona, PromptMode } from '@/interfaces/assistant';
44
import { EvaluationType } from '@/interfaces/evaluationType';
55
import {
66
ActivityStep,
@@ -44,6 +44,8 @@ export type ActivitySetting = {
4444

4545
export type AssistantsSetting = {
4646
assistants: AssistantPersona[];
47+
promptMode?: PromptMode;
48+
includeDetails?: boolean;
4749
};
4850

4951
export type NotParticipatingSetting = { ids: Member['id'][] };
@@ -124,5 +126,7 @@ export const defaultSettingsValues: AllSettingsType = {
124126
},
125127
assistants: {
126128
assistants: [],
129+
promptMode: PromptMode.Problem,
130+
includeDetails: false,
127131
},
128132
};

src/config/prompts.ts

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { TFunction } from 'i18next';
22

3-
import { RESPONSE_MAXIMUM_LENGTH } from './constants';
3+
import { RESPONSE_MAXIMUM_LENGTH } from '@/config/constants';
4+
import { PromptMode } from '@/interfaces/assistant';
45

56
export const DEFAULT_SYSTEM_PROMPT =
67
'You are part of a group of designers trying to solve a wicked problem. Help your group by proposing new ideas';
@@ -13,23 +14,69 @@ export const getSingleResponsePrompt = (prompt: string): string =>
1314
export const promptForSingleResponse = (
1415
problemStatement: string,
1516
t: TFunction<'prompts', undefined>,
16-
): string =>
17-
t('SINGLE_RESPONSE', {
18-
problemStatement,
19-
maxChars: RESPONSE_MAXIMUM_LENGTH,
20-
});
17+
details?: string,
18+
promptMode?: PromptMode,
19+
): string => {
20+
if (promptMode === PromptMode.Instructions) {
21+
return typeof details === 'undefined'
22+
? t('INSTRUCTIONS.SINGLE_RESPONSE', {
23+
instructions: problemStatement,
24+
maxChars: RESPONSE_MAXIMUM_LENGTH,
25+
})
26+
: t('INSTRUCTIONS.SINGLE_RESPONSE_WITH_DETAILS', {
27+
// TODO: Put this in translations
28+
instructions: problemStatement,
29+
details,
30+
maxChars: RESPONSE_MAXIMUM_LENGTH,
31+
});
32+
}
33+
return typeof details === 'undefined'
34+
? t('PROBLEM.SINGLE_RESPONSE', {
35+
problemStatement,
36+
maxChars: RESPONSE_MAXIMUM_LENGTH,
37+
})
38+
: t('PROBLEM.SINGLE_RESPONSE_WITH_DETAILS', {
39+
// TODO: Put this in translations
40+
problemStatement,
41+
details,
42+
maxChars: RESPONSE_MAXIMUM_LENGTH,
43+
});
44+
};
2145

2246
export const promptForSingleResponseAndProvideResponses = (
2347
problemStatement: string,
2448
responses: string[],
2549
t: TFunction<'prompts', undefined>,
50+
details?: string,
51+
promptMode?: PromptMode,
2652
): string => {
2753
const responsesString = responses.map(
2854
(r) => `<solution>\n${r}\n</solution>\n`,
2955
);
30-
return t('SINGLE_RESPONSE_AND_PROVIDE_RESPONSES', {
31-
problemStatement,
32-
responses: responsesString,
33-
maxChars: RESPONSE_MAXIMUM_LENGTH,
34-
});
56+
if (promptMode === PromptMode.Instructions) {
57+
return typeof details === 'undefined'
58+
? t('INSTRUCTIONS.SINGLE_RESPONSE_AND_PROVIDE_RESPONSES', {
59+
instructions: problemStatement,
60+
responses: responsesString,
61+
maxChars: RESPONSE_MAXIMUM_LENGTH,
62+
})
63+
: t('INSTRUCTIONS.SINGLE_RESPONSE_WITH_DETAILS_AND_PROVIDE_RESPONSES', {
64+
instructions: problemStatement,
65+
details,
66+
responses: responsesString,
67+
maxChars: RESPONSE_MAXIMUM_LENGTH,
68+
});
69+
}
70+
return typeof details === 'undefined'
71+
? t('PROBLEM.SINGLE_RESPONSE_AND_PROVIDE_RESPONSES', {
72+
instructions: problemStatement,
73+
responses: responsesString,
74+
maxChars: RESPONSE_MAXIMUM_LENGTH,
75+
})
76+
: t('PROBLEM.SINGLE_RESPONSE_WITH_DETAILS_AND_PROVIDE_RESPONSES', {
77+
instructions: problemStatement,
78+
details,
79+
responses: responsesString,
80+
maxChars: RESPONSE_MAXIMUM_LENGTH,
81+
});
3582
};

src/hooks/useAssistants.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const useAssistants = (): UseAssistantsValues => {
4343
assistants,
4444
instructions,
4545
} = useSettings();
46+
47+
const { includeDetails, promptMode } = assistants;
4648
const { postAppDataAsync } = useAppDataContext();
4749

4850
const { assistantsResponsesSets, round, allResponses, postResponse } =
@@ -157,12 +159,19 @@ const useAssistants = (): UseAssistantsValues => {
157159
instructions.title.content,
158160
responses,
159161
t,
162+
includeDetails ? instructions.details?.content : undefined,
163+
promptMode,
160164
),
161165
);
162166
}
163167
return promptAssistant(
164168
persona,
165-
promptForSingleResponse(instructions.title.content, t),
169+
promptForSingleResponse(
170+
instructions.title.content,
171+
t,
172+
includeDetails ? instructions.details?.content : undefined,
173+
promptMode,
174+
),
166175
);
167176
})
168177
.map((promise) =>

src/interfaces/assistant.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ export const makeEmptyAssistant = (id?: AssistantId): AssistantPersona => ({
2323
description: '',
2424
message: [],
2525
});
26+
27+
export enum PromptMode {
28+
Problem = 'problem',
29+
Instructions = 'instructions',
30+
}

src/langs/en/main.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@
9595
},
9696
"ASSISTANT": {
9797
"TITLE": "Assistants",
98+
"USE_DETAILS": "Use instructions details when prompting assistants.",
99+
"PROMPT_MODE_LABEL": "Select the prompting mode",
100+
"PROMPT_MODE_ITEMS": {
101+
"INSTRUCTIONS": "Instructions",
102+
"PROBLEM": "Problem"
103+
},
98104
"ADD": "Add an assistant",
99105
"EDIT_DIALOG": {
100106
"CHATBOT_NAME_LABEL": "Chatbot Name",

src/langs/en/prompts.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
{
2-
"SINGLE_RESPONSE": "We are given the following wicked problem:\n<problem>\n{{problemStatement}}\n</problem>\n\nGenerate a single solution to this challenge. Provide only the solution and limit it to {{maxChars}} characters.",
3-
"SINGLE_RESPONSE_AND_PROVIDE_RESPONSES": "We are given the following problem:\n<problem>\n{{problemStatement}}\n</problem>\n\nSo far, your teammates have proposed the following solutions to this problem:\n{{responses}}\nGenerate a single, disruptive and out-of-the-box solution for this challenge. Your solution should challenge conventional thinking and differ from the solutions proposed by the other participants. Try to match the tone and style of the given solutions.\nProvide only the solution. Do not enclose it in XML tags or any other format. Limit it to {{maxChars}} characters.",
2+
"PROBLEM": {
3+
"SINGLE_RESPONSE": "We are given the following wicked problem:\n<problem>\n{{problemStatement}}\n</problem>\n\nGenerate a single solution to this challenge. Provide only the solution and limit it to {{maxChars}} characters.",
4+
"SINGLE_RESPONSE_WITH_DETAILS": "We are given the following wicked problem:\n<problem>\n{{problemStatement}}\n</problem>\nAlong with it, the following details are provided:\n<details>\n{{details}}\n</details>\n\nGenerate a single solution to this challenge. Provide only the solution and limit it to {{maxChars}} characters.",
5+
"SINGLE_RESPONSE_AND_PROVIDE_RESPONSES": "We are given the following problem:\n<problem>\n{{problemStatement}}\n</problem>\n\nSo far, your teammates have proposed the following solutions to this problem:\n{{responses}}\nGenerate a single, disruptive and out-of-the-box solution for this challenge. Your solution should challenge conventional thinking and differ from the solutions proposed by the other participants. Try to match the tone and style of the given solutions.\nProvide only the solution. Do not enclose it in XML tags or any other format. Limit it to {{maxChars}} characters.",
6+
"SINGLE_RESPONSE_WITH_DETAILS_AND_PROVIDE_RESPONSES": "We are given the following problem:\n<problem>\n{{problemStatement}}\n</problem>\nAlong with it, the following details are provided:\n<details>{{details}}</details>\n\nSo far, your teammates have proposed the following solutions to this problem:\n{{responses}}\nGenerate a single, disruptive and out-of-the-box solution for this challenge. Your solution should challenge conventional thinking and differ from the solutions proposed by the other participants. Try to match the tone and style of the given solutions.\nProvide only the solution. Do not enclose it in XML tags or any other format. Limit it to {{maxChars}} characters."
7+
},
8+
"INSTRUCTIONS": {
9+
"SINGLE_RESPONSE": "We are given the following instructions:\n{{instructions}}\n\nFollow these instructions and provide an answer. Provide only a single answer and limit it to {{maxChars}} characters.",
10+
"SINGLE_RESPONSE_WITH_DETAILS": "We are given the following instructions:\n<instructions>\n{{instructions}}\n{{details}}\n</instructions>\n\nFollow these instructions and provide an answer. Provide only a single answer and limit it to {{maxChars}} characters.",
11+
"SINGLE_RESPONSE_AND_PROVIDE_RESPONSES": "We are given the following instructions:\n<instructions>\n{{instructions}}\n</instructions>\n\nFollow these instructions and provide an answer. So far, your teammates have proposed the following answers to this problem:\n{{responses}}\nYour answer should differ from the answers proposed by the other participants. Try to match the tone and style of the given answers.\nProvide only a single answer. Do not enclose it in XML tags or any other format. Limit it to {{maxChars}} characters.",
12+
"SINGLE_RESPONSE_WITH_DETAILS_AND_PROVIDE_RESPONSES": "We are given the following instructions:\n<instructions>\n{{instructions}}\n{{details}}\n</instructions>\n\nFollow these instructions and provide an answer. So far, your teammates have proposed the following answers to this problem:\n{{responses}}\nYour answer should differ from the answers proposed by the other participants. Try to match the tone and style of the given answers.\nProvide only a single answer. Do not enclose it in XML tags or any other format. Limit it to {{maxChars}} characters."
13+
},
414
"REFORMULATE": {
515
"SYSTEM": "You are an helpful assistant. You will help in reformulating short text that the user will give you.",
616
"USER_1": "I will give you a response. You need to reformulate it so that it has a neutral tone, is clearer and match the following problem:\n{{ problem }}\n\n{{ details }}The reformulated response must not exceed {{ maxChars }} characters. When answering, give me only the reformulated idea.",

src/langs/fr/prompts.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
{
2-
"SINGLE_RESPONSE": "We are given the following wicked problem:\n<problem>\n{{problemStatement}}\n</problem>\n\nGenerate a single solution to this challenge. Provide only the solution and limit it to {{maxChars}} characters.",
3-
"SINGLE_RESPONSE_AND_PROVIDE_RESPONSES": "We are given the following problem:\n<problem>\n{{problemStatement}}\n</problem>\n\nSo far, your teammates have proposed the following solutions to this problem:\n{{responses}}\nGenerate a single, disruptive and out-of-the-box solution for this challenge. Your solution should challenge conventional thinking and differ from the solutions proposed by the other participants. Try to match the tone and style of the given solutions.\nProvide only the solution, not enclosed in any format (no XML tags), and limit it to {{maxChars}} characters.",
2+
"PROBLEM": {
3+
"SINGLE_RESPONSE": "Nous avons reçu le problème complexe suivant :\n<problem>\n{{problemStatement}}\n</problem>\n\nGénère une seule solution à ce défi. Fourni une seule solution et limite-toi à {{maxChars}} charactères.",
4+
"SINGLE_RESPONSE_WITH_DETAILS": "Nous avons reçu le problème complexe suivant :\n<problem>\n{{problemStatement}}\n</problem>\nAvec ce problème, les détails suivants sont donnés :\n<details>\n{{details}}\n</details>\n\nGénère une seule solution à ce défi. Fourni une seule solution et limite-toi à {{maxChars}} charactères.",
5+
"SINGLE_RESPONSE_AND_PROVIDE_RESPONSES": "Nous avons reçu le problème complexe suivant :\n<problem>\n{{problemStatement}}\n</problem>\n\nJusqu'à maintenant, vos co-équipiers ont proposé les solutions suivantes à ce problème :\n{{responses}}\nGénère une seule réponse disruptive et originale pour ce défi. Ta solution doit défier les modes de pensée conventionnels et être différente des solutions proposées par les autres participants. Essaie d'imiter le ton et le style des solutions déjà proposées.\n Fourni uniquement une seule solution. N'encapsule pas ta réponse dans des tags XML ou aucun autre format. Limite-toi à {{maxChars}} charactères.",
6+
"SINGLE_RESPONSE_WITH_DETAILS_AND_PROVIDE_RESPONSES": "Nous avons reçu le problème complexe suivant :\n<problem>\n{{problemStatement}}\n</problem>\nAvec ce problème, les détails suivants sont donnés :\n<details>{{details}}</details>\n\nJusqu'à maintenant, vos co-équipiers ont proposé les solutions suivantes à ce problème :\n{{responses}}\nGénère une seule réponse disruptive et originale pour ce défi. Ta solution doit défier les modes de pensée conventionnels et être différente des solutions proposées par les autres participants. Essaie d'imiter le ton et le style des solutions déjà proposées.\n Fourni uniquement une seule solution. N'encapsule pas ta réponse dans des tags XML ou aucun autre format. Limite-toi à {{maxChars}} charactères."
7+
},
8+
"INSTRUCTIONS": {
9+
"SINGLE_RESPONSE": "Nous avons reçu les instructions suivantes :\n{{instructions}}\n\nSuis ces instructions et fourni une réponse. Fourni une seule réponse et limite-toi à {{maxChars}} charactères.",
10+
"SINGLE_RESPONSE_WITH_DETAILS": "Nous avons reçu les instructions suivantes :\n<instructions>\n{{instructions}}\n{{details}}\n</instructions>\n\nSuis ces instructions et fourni une réponse. Fourni une seule réponse et limite-toi à {{maxChars}} charactères.",
11+
"SINGLE_RESPONSE_AND_PROVIDE_RESPONSES": "Nous avons reçu les instructions suivantes :\n<instructions>\n{{instructions}}\n</instructions>\n\nSuis ces instructions et fourni une réponse. Jusqu'à maintenant, vos co-équipiers ont proposé les réponses suivantes :\n{{responses}}\nTa réponse doit être différente des réponses des autres participants. Essaie d'imiter le ton et le style des solutions déjà proposées.\n Fourni uniquement une seule solution. N'encapsule pas ta réponse dans des tags XML ou aucun autre format. Limite-toi à {{maxChars}} charactères.",
12+
"SINGLE_RESPONSE_WITH_DETAILS_AND_PROVIDE_RESPONSES": "Nous avons reçu les instructions suivantes :\n<instructions>\n{{instructions}}\n{{details}}\n</instructions>\n\nSuis ces instructions et fourni une réponse. Jusqu'à maintenant, vos co-équipiers ont proposé les réponses suivantes :\n{{responses}}\nTa réponse doit être différente des réponses des autres participants. Essaie d'imiter le ton et le style des solutions déjà proposées.\n Fourni uniquement une seule solution. N'encapsule pas ta réponse dans des tags XML ou aucun autre format. Limite-toi à {{maxChars}} charactères."
13+
},
414
"REFORMULATE": {
515
"SYSTEM": "Tu es un assistant serviable. Tu vas aider à reformuler de court textes que l'utilisateur va te donner.",
616
"USER_1": "Je vais te donner une réponse. Tu dois la reformuler pour que cette dernière aie un ton neutre, soit plus clair et corresponde au problème suivant:\n{{ problem }}\n\n{{ details }}\nLa réponse reformulée ne dois pas dépasser {{ maxChars }} charactères. Donne moi uniquement la réponse reformulée.",

src/modules/orchestration/StepsButton.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import LinearProgress from '@mui/material/LinearProgress';
1010
import Stack from '@mui/material/Stack';
1111
import Tooltip from '@mui/material/Tooltip';
1212
import useSteps from '@/hooks/useSteps';
13+
import Collapse from '@mui/material/Collapse';
14+
import CircularProgress from '@mui/material/CircularProgress';
1315
import CommandButton from './CommandButton';
1416
import WarningPreviousStepDialog from './WarningPreviousStepDialog';
1517
import useStepTimer from '../common/stepTimer/useStepTimer';
@@ -127,6 +129,9 @@ const StepsButton: FC<StepsButtonProps> = ({ enable }) => {
127129
{t('NEXT_STEP')}
128130
</CommandButton>
129131
</Tooltip>
132+
<Collapse in={isChangingStep}>
133+
<CircularProgress />
134+
</Collapse>
130135
<WarningPreviousStepDialog
131136
open={openWarningPreviousStepDialog}
132137
onConfirm={goToPreviousStep}

src/modules/settings/assistant/Assistant.tsx

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC, useState } from 'react';
1+
import { ChangeEvent, FC, useState } from 'react';
22
import { useTranslation } from 'react-i18next';
33

44
import Button from '@mui/material/Button';
@@ -8,11 +8,22 @@ import cloneDeep from 'lodash.clonedeep';
88
import { v4 as uuidv4 } from 'uuid';
99

1010
import { AssistantsSetting } from '@/config/appSettingsType';
11-
import { AssistantPersona, makeEmptyAssistant } from '@/interfaces/assistant';
11+
import {
12+
AssistantPersona,
13+
PromptMode,
14+
makeEmptyAssistant,
15+
} from '@/interfaces/assistant';
1216
import SectionTitle from '@/modules/adminPanel/SectionTitle';
1317

14-
import AssistantCard from './AssistantCard';
18+
import FormGroup from '@mui/material/FormGroup';
19+
import FormControlLabel from '@mui/material/FormControlLabel';
20+
import Switch from '@mui/material/Switch';
21+
import FormControl from '@mui/material/FormControl';
22+
import InputLabel from '@mui/material/InputLabel';
23+
import Select, { SelectChangeEvent } from '@mui/material/Select';
24+
import MenuItem from '@mui/material/MenuItem';
1525
import AssistantDialog from './AssistantDialog';
26+
import AssistantCard from './AssistantCard';
1627

1728
interface AssistantProps {
1829
assistants: AssistantsSetting;
@@ -27,7 +38,24 @@ const Assistant: FC<AssistantProps> = ({
2738
keyPrefix: 'SETTINGS.ASSISTANT',
2839
});
2940
const [editedAssistant, setEditedAssistant] = useState<AssistantPersona>();
30-
const { assistants } = assistantsSetting;
41+
const { assistants, includeDetails, promptMode } = assistantsSetting;
42+
43+
const handleIncludeDetailsChange = (
44+
_e: ChangeEvent<HTMLInputElement>,
45+
checked: boolean,
46+
): void => {
47+
onChange({
48+
...assistantsSetting,
49+
includeDetails: checked,
50+
});
51+
};
52+
53+
const handlePromptModeChange = (e: SelectChangeEvent): void => {
54+
onChange({
55+
...assistantsSetting,
56+
promptMode: e.target.value as PromptMode,
57+
});
58+
};
3159

3260
const handleSave = (newAssistant: AssistantPersona): void => {
3361
const newAssistants = cloneDeep(assistants);
@@ -38,6 +66,7 @@ const Assistant: FC<AssistantProps> = ({
3866
newAssistants[index] = newAssistant;
3967
}
4068
onChange({
69+
...assistantsSetting,
4170
assistants: newAssistants,
4271
});
4372
setEditedAssistant(undefined);
@@ -58,6 +87,34 @@ const Assistant: FC<AssistantProps> = ({
5887
return (
5988
<>
6089
<SectionTitle>{t('TITLE')}</SectionTitle>
90+
<FormGroup>
91+
<FormControlLabel
92+
control={
93+
<Switch
94+
checked={includeDetails}
95+
onChange={handleIncludeDetailsChange}
96+
/>
97+
}
98+
label={t('USE_DETAILS')}
99+
/>
100+
</FormGroup>
101+
<FormControl>
102+
<InputLabel id="prompt-mode-label">{t('PROMPT_MODE_LABEL')}</InputLabel>
103+
<Select
104+
labelId="demo-simple-select-label"
105+
id="demo-simple-select"
106+
value={promptMode}
107+
label={t('PROMPT_MODE_LABEL')}
108+
onChange={handlePromptModeChange}
109+
>
110+
<MenuItem value={PromptMode.Instructions}>
111+
{t('PROMPT_MODE_ITEMS.INSTRUCTIONS')}
112+
</MenuItem>
113+
<MenuItem value={PromptMode.Problem}>
114+
{t('PROMPT_MODE_ITEMS.PROBLEM')}
115+
</MenuItem>
116+
</Select>
117+
</FormControl>
61118
<Grid container spacing={1}>
62119
{assistants.map((persona) => (
63120
<Grid key={persona.id} item>

0 commit comments

Comments
 (0)