mirror of
https://github.com/Hopiu/llm.git
synced 2026-04-29 17:34:45 +00:00
Merge branch 'main' into chat-edit-prompt
This commit is contained in:
commit
28817c6a59
8 changed files with 114 additions and 10 deletions
|
|
@ -31,6 +31,13 @@ The `llm embed` command returns a JSON array of floating point numbers directly
|
|||
```
|
||||
You can omit the `-m/--model` option if you set a {ref}`default embedding model <embeddings-cli-embed-models-default>`.
|
||||
|
||||
You can also set the `LLM_EMBEDDING_MODEL` environment variable to set a default model for all `llm embed` commands in the current shell session:
|
||||
|
||||
```bash
|
||||
export LLM_EMBEDDING_MODEL=3-small
|
||||
llm embed -c 'This is some content'
|
||||
```
|
||||
|
||||
LLM also offers a binary storage format for embeddings, described in {ref}`embeddings storage format <embeddings-storage>`.
|
||||
|
||||
You can output embeddings using that format as raw bytes using `--format blob`, or in hexadecimal using `--format hex`, or in Base64 using `--format base64`:
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ llm logs -c --json --expand
|
|||
|
||||
LLM plugins can provide custom fragment loaders which do useful things.
|
||||
|
||||
One example is the [llm-fragments-github plugin](https://github.com/simonw/llm-fragments-github). This can convert the file from a public GitHub repository into a list of fragments, allowing you to ask questions about the full repository.
|
||||
One example is the [llm-fragments-github plugin](https://github.com/simonw/llm-fragments-github). This can convert the files from a public GitHub repository into a list of fragments, allowing you to ask questions about the full repository.
|
||||
|
||||
Here's how to try that out:
|
||||
|
||||
|
|
@ -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"
|
||||
```
|
||||
|
|
|
|||
20
docs/help.md
20
docs/help.md
|
|
@ -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
|
||||
```
|
||||
|
|
|
|||
|
|
@ -11,6 +11,14 @@ Features to consider for your model plugin include:
|
|||
- Handling {ref}`attachments <advanced-model-plugins-attachments>` (images, audio and more) for multi-modal models.
|
||||
- Tracking {ref}`token usage <advanced-model-plugins-usage>` for models that charge by the token.
|
||||
|
||||
(advanced-model-plugins-lazy)=
|
||||
|
||||
## Tip: lazily load expensive dependencies
|
||||
|
||||
If your plugin depends on an expensive library such as [PyTorch](https://pytorch.org/) you should avoid importing that dependency (or a dependency that uses that dependency) at the top level of your module. Expensive imports in plugins mean that even simple commands like `llm --help` can take a long time to run.
|
||||
|
||||
Instead, move those imports to inside the methods that need them. Here's an example [change to llm-sentence-transformers](https://github.com/simonw/llm-sentence-transformers/commit/f87df71e8a652a8cb05ad3836a79b815bcbfa64b) that shaved 1.8 seconds off the time it took to run `llm --help`!
|
||||
|
||||
(advanced-model-plugins-api-keys)=
|
||||
|
||||
## Models that accept API keys
|
||||
|
|
|
|||
|
|
@ -30,8 +30,13 @@ Or if you know the name is too long to type, use `-q` once or more to provide se
|
|||
```bash
|
||||
llm 'Ten names for cheesecakes' -q 4o -q mini
|
||||
```
|
||||
To change the default model for the current session, set the `LLM_MODEL` environment variable:
|
||||
```bash
|
||||
export LLM_MODEL=gpt-4.1-mini
|
||||
llm 'Ten names for cheesecakes' # Uses gpt-4.1-mini
|
||||
```
|
||||
|
||||
You can also send a prompt to standard input, for example:
|
||||
You can send a prompt directly to standard input like this:
|
||||
```bash
|
||||
echo 'Ten names for cheesecakes' | llm
|
||||
```
|
||||
|
|
|
|||
32
llm/cli.py
32
llm/cli.py
|
|
@ -292,7 +292,7 @@ def cli():
|
|||
@cli.command(name="prompt")
|
||||
@click.argument("prompt", required=False)
|
||||
@click.option("-s", "--system", help="System prompt to use")
|
||||
@click.option("model_id", "-m", "--model", help="Model to use")
|
||||
@click.option("model_id", "-m", "--model", help="Model to use", envvar="LLM_MODEL")
|
||||
@click.option(
|
||||
"-d",
|
||||
"--database",
|
||||
|
|
@ -783,7 +783,7 @@ def prompt(
|
|||
|
||||
@cli.command()
|
||||
@click.option("-s", "--system", help="System prompt to use")
|
||||
@click.option("model_id", "-m", "--model", help="Model to use")
|
||||
@click.option("model_id", "-m", "--model", help="Model to use", envvar="LLM_MODEL")
|
||||
@click.option(
|
||||
"_continue",
|
||||
"-c",
|
||||
|
|
@ -2293,6 +2293,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):
|
||||
|
|
@ -2362,7 +2382,9 @@ def uninstall(packages, yes):
|
|||
type=click.Path(exists=True, readable=True, allow_dash=True),
|
||||
help="File to embed",
|
||||
)
|
||||
@click.option("-m", "--model", help="Embedding model to use")
|
||||
@click.option(
|
||||
"-m", "--model", help="Embedding model to use", envvar="LLM_EMBEDDING_MODEL"
|
||||
)
|
||||
@click.option("--store", is_flag=True, help="Store the text itself in the database")
|
||||
@click.option(
|
||||
"-d",
|
||||
|
|
@ -2504,7 +2526,9 @@ def embed(
|
|||
"--batch-size", type=int, help="Batch size to use when running embeddings"
|
||||
)
|
||||
@click.option("--prefix", help="Prefix to add to the IDs", default="")
|
||||
@click.option("-m", "--model", help="Embedding model to use")
|
||||
@click.option(
|
||||
"-m", "--model", help="Embedding model to use", envvar="LLM_EMBEDDING_MODEL"
|
||||
)
|
||||
@click.option(
|
||||
"--prepend",
|
||||
help="Prepend this string to all content before embedding",
|
||||
|
|
|
|||
|
|
@ -624,6 +624,18 @@ def test_schema(mock_model, use_pydantic):
|
|||
assert response.prompt.schema == dog_schema
|
||||
|
||||
|
||||
def test_model_environment_variable(monkeypatch):
|
||||
monkeypatch.setenv("LLM_MODEL", "echo")
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
cli,
|
||||
["--no-stream", "hello", "-s", "sys"],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert result.output == "system:\nsys\n\nprompt:\nhello\n"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("use_filename", (True, False))
|
||||
def test_schema_via_cli(mock_model, tmpdir, monkeypatch, use_filename):
|
||||
user_path = tmpdir / "user"
|
||||
|
|
|
|||
|
|
@ -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() == {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue