prompts

The instruction text of the tutor. You can change it on the Settings page.

Each prompt of the tutor has two parts. The variable parts (the concept, the thread, the JSON shape) stay in code. The instruction text is in this registry. Each prompt has a name, a plain label, a note on what it changes, and its default text from code. The Settings page shows each prompt, and you can change its text there. The tutor reads each prompt when it calls the model. Thus a change works on the next question, with no restart.

Import the tools that this module uses. The settings come from settings only when a prompt is read, so the import stays light.

The registry

register adds a prompt to PROMPTS and returns its default text. A check can refuse a bad text: it raises ValueError with a plain message.


source

register

def register(
    name:str, label:str, note:str, dflt:str, check:NoneType=None
)->str:

Add the prompt name with a plain label, a note on what it changes, its dflt text and an optional check. Return dflt.

lines gives the lines of a text that are not empty. need_lines makes a check that refuses a text without exactly n such lines.


source

need_lines

def need_lines(
    n:int, what:str
):

A check that refuses a text that does not have n lines that are not empty.


source

lines

def lines(
    text:str
)->list:

The lines of text that are not empty, without spaces at the ends.

Read and save

prompt gives the saved text of a prompt, else its default. set_prompt saves a text in the settings, under the prompts key. An empty text, or a text that is the same as the default, removes the saved text. Then the default is in use again, also when a new version changes the default.


source

set_prompt

def set_prompt(
    name:str, text:str=''
)->str:

Save the text of the prompt name. An empty text uses the default. A text that fails the check raises ValueError. Return the text in use.


source

prompt

def prompt(
    name:str
)->str:

The text of the prompt name now: the saved text, else the default.


source

saved

def saved()->dict:

The saved prompt texts: name -> text.

Tests

A small prompt with a check of 2 lines. Its default is in use at first.

register('greet', 'Greeting', 'The first line.', 'Say hello.\nSay your name.', need_lines(2, 'The greeting'))
test_eq(prompt('greet'), 'Say hello.\nSay your name.')

A saved text is in use at once, and the settings keep it under prompts.

test_eq(set_prompt('greet', 'Say hi.\r\nSay your job.\n'), 'Say hi.\nSay your job.')
test_eq((prompt('greet'), saved()), ('Say hi.\nSay your job.', {'greet': 'Say hi.\nSay your job.'}))

A text that fails the check is refused with a plain message, and the saved text stays.

test_fail(lambda: set_prompt('greet', 'Only one line.'), contains='needs 2 lines')
test_eq(prompt('greet'), 'Say hi.\nSay your job.')

An empty text, or only spaces, removes the saved text, so the default is in use again. A text that is the same as the default is not kept.

test_eq(set_prompt('greet', '  \n '), 'Say hello.\nSay your name.')
set_prompt('greet', 'Say hello.\nSay your name.')
test_eq(saved(), {})

An unknown name is an error. Then the test prompt goes away.

test_fail(lambda: prompt('nope'))
del PROMPTS['greet']