summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--doc/vim-ai.txt2
-rw-r--r--py/utils.py33
3 files changed, 36 insertions, 6 deletions
diff --git a/README.md b/README.md
index e8ca86a..c1cac6b 100644
--- a/README.md
+++ b/README.md
@@ -185,7 +185,7 @@ Note that the randomness of responses heavily depends on the [`temperature`](htt
## Roles
-In the context of this plugin, a role means a re-usable AI instruction and/or configuration. Roles are defined in the configuration `.ini` file. For example by defining a `grammar` role:
+In the context of this plugin, a role means a re-usable AI instruction and/or configuration. Roles are defined in the configuration `.ini` file. For example by defining a `grammar` and `o1-mini` role:
```vim
let g:vim_ai_roles_config_file = '/path/to/my/roles.ini'
@@ -200,6 +200,9 @@ prompt = fix spelling and grammar
[grammar.options]
temperature = 0.4
+[grammar]
+prompt = fix spelling and grammar
+
[o1-mini]
[o1-mini.options]
stream = 0
@@ -211,6 +214,8 @@ initial_prompt =
Now you can select text and run it with command `:AIEdit /grammar`.
+You can also combine roles `:AI /o1-mini /grammar helo world!`
+
See [roles-example.ini](./roles-example.ini) for more examples.
## Key bindings
diff --git a/doc/vim-ai.txt b/doc/vim-ai.txt
index 0d9a410..241e33b 100644
--- a/doc/vim-ai.txt
+++ b/doc/vim-ai.txt
@@ -202,6 +202,8 @@ Example of a role: >
[grammar.options]
temperature = 0.4
+
+Now you can select text and run it with command `:AIEdit /grammar`.
See roles-example.ini for more examples.
The roles in g:vim_ai_roles_config_file are converted to a Vim dictionary whose
diff --git a/py/utils.py b/py/utils.py
index f81eeb8..849152e 100644
--- a/py/utils.py
+++ b/py/utils.py
@@ -334,17 +334,40 @@ empty_role_options = {
'options_chat': {},
}
+def parse_roles(prompt):
+ chunks = prompt.split()
+ roles = []
+ for chunk in chunks:
+ if not chunk.startswith("/"):
+ break
+ roles.append(chunk)
+ return [raw_role[1:] for raw_role in roles]
+
+def merge_role_configs(configs):
+ merged_options = empty_role_options
+ merged_role = {}
+ for config in configs:
+ options = config['options']
+ merged_options = {
+ 'options_default': { **merged_options['options_default'], **options['options_default'] },
+ 'options_complete': { **merged_options['options_complete'], **options['options_complete'] },
+ 'options_chat': { **merged_options['options_chat'], **options['options_chat'] },
+ }
+ merged_role ={ **merged_role, **config['role'] }
+ return { 'role': merged_role, 'options': merged_options }
+
def parse_prompt_and_role(raw_prompt):
prompt = raw_prompt.strip()
- role = re.split(' |:', prompt)[0]
- if not role.startswith('/'):
+ roles = parse_roles(prompt)
+ if not roles:
# does not require role
return (prompt, empty_role_options)
- prompt = prompt[len(role):].strip()
- role = role[1:]
+ last_role = roles[-1]
+ prompt = prompt[prompt.index(last_role) + len(last_role):].strip()
- config = load_role_config(role)
+ role_configs = [load_role_config(role) for role in roles]
+ config = merge_role_configs(role_configs)
if 'prompt' in config['role'] and config['role']['prompt']:
delim = '' if prompt.startswith(':') else ':\n'
prompt = config['role']['prompt'] + delim + prompt