llm fragments loaders, closes #941

This commit is contained in:
Simon Willison 2025-04-20 07:56:06 -07:00
parent e78e1fceb2
commit c9f64096c9
4 changed files with 72 additions and 4 deletions

View file

@ -146,3 +146,26 @@ Running `llm logs -c` will show that this prompt incorporated 26 fragments, one
Running `llm logs -c --usage --expand` includes token usage information and turns each fragment ID into a full copy of that file. [Here's the output of that command](https://gist.github.com/simonw/c9bbbc5f6560b01f4b7882ac0194fb25).
See the {ref}`register_fragment_loaders() plugin hook <plugin-hooks-register-fragment-loaders>` documentation for details on writing your own custom fragment plugin.
(fragments-loaders)=
## Listing available fragment prefixes
The `llm fragments loaders` command shows all prefixes that have been installed by plugins, along with their documentation:
```bash
llm install llm-fragments-github
llm fragments loaders
```
Example output:
```
github:
Load files from a GitHub repository as fragments.
Argument is a GitHub repository URL or username/repository
issue:
Fetch GitHub issue and comments as Markdown
argument is either "owner/repo/NUMBER"
or "https://github.com/owner/repo/issues/NUMBER"
```

View file

@ -688,10 +688,11 @@ Options:
--help Show this message and exit.
Commands:
list* List current fragments
remove Remove a fragment alias
set Set an alias for a fragment
show Display the fragment stored under an alias or hash
list* List current fragments
loaders Show fragment loaders registered by plugins
remove Remove a fragment alias
set Set an alias for a fragment
show Display the fragment stored under an alias or hash
```
(help-fragments-list)=
@ -753,6 +754,17 @@ Options:
--help Show this message and exit.
```
(help-fragments-loaders)=
#### llm fragments loaders --help
```
Usage: llm fragments loaders [OPTIONS]
Show fragment loaders registered by plugins
Options:
--help Show this message and exit.
```
(help-plugins)=
### llm plugins --help
```

View file

@ -2283,6 +2283,26 @@ def fragments_remove(alias):
)
@fragments.command(name="loaders")
def fragments_loaders():
"""Show fragment loaders registered by plugins"""
from llm import get_fragment_loaders
found = False
for prefix, loader in get_fragment_loaders().items():
if found:
# Extra newline on all after the first
click.echo("")
found = True
docs = "Undocumented"
if loader.__doc__:
docs = textwrap.dedent(loader.__doc__).strip()
click.echo(f"{prefix}:")
click.echo(textwrap.indent(docs, " "))
if not found:
click.echo("No fragment loaders found")
@cli.command(name="plugins")
@click.option("--all", help="Include built-in default plugins", is_flag=True)
def plugins_list(all):

View file

@ -94,6 +94,7 @@ def test_register_fragment_loaders(logs_db):
assert get_fragment_loaders() == {}
def single_fragment(argument):
"This is the fragment documentation"
return llm.Fragment("single", "single")
def three_fragments(argument):
@ -127,6 +128,18 @@ def test_register_fragment_loaders(logs_db):
assert result.exit_code == 0
expected = "prompt:\n" "one:x\n" "two:x\n" "three:x\n"
assert expected in result.output
# And the llm fragments loaders command:
result2 = runner.invoke(cli.cli, ["fragments", "loaders"])
assert result2.exit_code == 0
expected2 = (
"single:\n"
" This is the fragment documentation\n"
"\n"
"three:\n"
" Undocumented\n"
)
assert result2.output == expected2
finally:
plugins.pm.unregister(name="FragmentLoadersPlugin")
assert get_fragment_loaders() == {}