Metadata-Version: 2.2
Name: ragkit-promptkit
Version: 0.1.0
Summary: A prompt template engine for LLM apps: validated variables, reusable few-shot blocks, and clean chat/message construction.
Author-email: Meet2147 <meetjethwa3@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/Meet2147/pythonLibraries/tree/main/promptkit
Project-URL: Repository, https://github.com/Meet2147/pythonLibraries
Project-URL: Issues, https://github.com/Meet2147/pythonLibraries/issues
Keywords: prompt,template,llm,few-shot,chat,genai
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE

<p align="center">
  <img src="https://raw.githubusercontent.com/Meet2147/pythonLibraries/main/promptkit/assets/logo.png" alt="promptkit" width="460">
</p>

<p align="center">
  <a href="https://pypi.org/project/ragkit-promptkit/"><img src="https://img.shields.io/pypi/v/ragkit-promptkit.svg" alt="PyPI"></a>
  <img src="https://img.shields.io/pypi/pyversions/ragkit-promptkit.svg" alt="Python versions">
  <img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License: MIT">
</p>

# promptkit

A prompt template engine for LLM apps: validated variables, reusable few-shot blocks, and clean chat/message construction.

> Part of the **ragkit** suite. Install with `pip install ragkit-promptkit`, then `import promptkit`.

`promptkit` replaces scattered f-strings that silently break when a variable is missing. You define templates once, get up-front validation of required variables, compose few-shot prompts, and build OpenAI-style message lists without hand-assembling dicts. Zero third-party dependencies -- standard library only, Python 3.8+.

## Install

```bash
pip install ragkit-promptkit
```

Local development (from `promptkit/`):

```bash
pip install -e .
```

## Quick Start

Define a template, inspect its variables, and render it:

```python
from promptkit import PromptTemplate

tmpl = PromptTemplate("Summarize the following {kind} in {n} sentences:\n\n{text}")

print(tmpl.variables)   # {'kind', 'n', 'text'}

print(tmpl.render(kind="article", n=3, text="..."))
```

`render()` also accepts a single dict:

```python
tmpl.render({"kind": "article", "n": 3, "text": "..."})
```

### Missing variables are reported all at once

If a referenced variable has no value (and no default), you get a
`MissingVariableError` listing **every** missing name -- not just the first:

```python
from promptkit import PromptTemplate, MissingVariableError

tmpl = PromptTemplate("{greeting}, {name}! Welcome to {place}.")

try:
    tmpl.render(greeting="Hello")
except MissingVariableError as exc:
    print(exc)          # Missing required variable(s): 'name', 'place'
    print(exc.missing)  # ['name', 'place']
```

Extra/unknown keyword arguments are ignored, so you can safely pass a shared
context dict to many templates.

### Literal braces

Use `{{` and `}}` for literal braces (same rules as `str.format`):

```python
PromptTemplate('Return JSON like {{"score": {n}}}').render(n=5)
# Return JSON like {"score": 5}
```

## Defaults and `partial()`

Provide `defaults` for optional variables, and use `partial()` to bake in some
values while leaving the rest open:

```python
from promptkit import PromptTemplate

tmpl = PromptTemplate(
    "You are a {tone} assistant. Answer: {question}",
    defaults={"tone": "friendly"},
)

tmpl.render(question="What is Python?")
# "You are a friendly assistant. Answer: What is Python?"

# Bake in the tone, get a new reusable template:
sarcastic = tmpl.partial(tone="sarcastic")
sarcastic.render(question="What is Python?")
# "You are a sarcastic assistant. Answer: What is Python?"
```

An explicit value always overrides a default. `partial()` returns a new
template and never mutates the original.

## Few-shot prompts

`FewShotTemplate` stitches a `prefix`, a list of rendered `examples`, and a
`suffix` (which usually holds the final user query):

```python
from promptkit import FewShotTemplate

few = FewShotTemplate(
    example_template="Q: {q}\nA: {a}",
    examples=[
        {"q": "2 + 2", "a": "4"},
        {"q": "3 * 3", "a": "9"},
    ],
    prefix="Solve the math problems.",
    suffix="Q: {question}\nA:",
    example_separator="\n\n",
)

# Add more examples dynamically:
few.add_example(q="10 - 4", a="6")

print(few.render(question="7 + 5"))
```

Output:

```
Solve the math problems.

Q: 2 + 2
A: 4

Q: 3 * 3
A: 9

Q: 10 - 4
A: 6

Q: 7 + 5
A:
```

Missing-variable validation applies across the prefix, examples, and suffix.

## Chat prompts -> message dicts

`ChatPromptTemplate` builds OpenAI-style `list[dict]` message payloads. Each
message content is rendered with the same `PromptTemplate` rules, and missing
variables are aggregated across **all** messages:

```python
from promptkit import ChatPromptTemplate, system, user, assistant

chat = ChatPromptTemplate.from_messages([
    system("You are a helpful {role}."),
    user("Explain {topic} to a {level} audience."),
])

messages = chat.render(role="tutor", topic="recursion", level="beginner")
# [
#   {"role": "system", "content": "You are a helpful tutor."},
#   {"role": "user", "content": "Explain recursion to a beginner audience."},
# ]
```

Pass `messages` straight to your LLM client. The `system`, `user`, and
`assistant` helpers just return `(role, template)` tuples. If you prefer typed
objects, `chat.render_messages(...)` returns `Message(role, content)` dataclass
instances (each has `.to_dict()`).

## Prompt registry and versioning

`PromptRegistry` is a tiny in-memory store for named, versioned prompts. `get()`
returns the latest version by default:

```python
from promptkit import PromptRegistry, PromptTemplate

registry = PromptRegistry()

registry.register(PromptTemplate("Summarize: {text}", name="summarize", version="1.0"))
registry.register(PromptTemplate("TL;DR the following:\n{text}", name="summarize", version="2.0"))

registry.list()                       # ['summarize']
registry.get("summarize")             # v2.0 (latest)
registry.get("summarize", version="1.0")  # the v1.0 template

latest = registry.get("summarize")
latest.render(text="...")
```

Versions are compared numerically when they look like dotted numbers
(`"1.0"`, `"2.3"`), falling back to string comparison otherwise.

## API summary

| Object | Purpose |
| --- | --- |
| `PromptTemplate` | Single-string template with `{var}` placeholders, defaults, `partial()`, and `.variables`. |
| `FewShotTemplate` | Prefix + examples + suffix composition with `add_example()`. |
| `ChatPromptTemplate` | Renders `(role, template)` pairs to message dicts. |
| `Message` | `dataclass(role, content)` with `.to_dict()`. |
| `system` / `user` / `assistant` | Helpers returning `(role, template)` tuples. |
| `PromptRegistry` | In-memory `register` / `get` / `list` with versioning. |
| `MissingVariableError` | Raised with `.missing` listing every unresolved variable. |

## License

MIT
