Metadata-Version: 2.5
Name: render-lab-tasks-llm
Version: 0.1.0
Summary: Provider-agnostic classification and summarization for Render Workflows
Project-URL: Repository, https://github.com/render-lab/render-tasks-python
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.12
Requires-Dist: anthropic<1,>=0.125
Requires-Dist: httpx<0.29,>=0.28
Requires-Dist: openai<3,>=2.54
Requires-Dist: redis<7,>=6.4
Requires-Dist: render==1.0.1
Description-Content-Type: text/markdown

# render-lab-tasks-llm

Provider-agnostic `llm.classify` and `llm.summarize` tasks for Render Workflows.
This is a starter subset of the TypeScript pack. Other LLM tasks, including
ledger opening/reporting and skill loading, have not yet been ported.

Not yet published to PyPI. Install from this repository:

```sh
uv pip install ./packages/tasks-llm
```

Import `app`, `classify`, `classify_impl`, `summarize`, and `summarize_impl` from
`render_lab_tasks_llm.tasks`. Combine pack apps with `Workflows.from_workflows`.
Run wrapped tasks with `await ctx.run(classify, input)`; inject `LlmDeps(chat=...)`
into the raw implementations for tests or custom task wrappers.

## Contracts

`classify` accepts `text`, `labels` (objects with `name` and optional `description`),
optional `maxLabels` (default 3), `model`, and `ledger`. It returns `labels`,
optional `reasoning`, resolved `model`, and optional `usage`. Unknown/non-string
labels are removed, duplicates are removed before capping, and malformed model
JSON yields an empty label list, matching TypeScript. This is prompt-based
classification, not a guarantee of semantic correctness.

`summarize` accepts `text`, optional `instructions`, `maxWords` (default 120),
`model`, and `ledger`. It returns trimmed `summary`, resolved `model`, and optional
`usage`. The word limit is a prompt target, not hard truncation.

Missing or null optional defaults behave like the TS implementation. Python
additionally rejects negative, boolean, and nonintegral `maxLabels`/`maxWords`
before calling a provider. Zero is valid. Optional result keys are omitted when
unavailable. Unknown model prices do not become zero-dollar estimates.

## Providers and environment

Credentials and configuration are read when a task runs, never during imports.

| Variable | Purpose |
| --- | --- |
| LLM_MODEL | Default provider-prefixed model; otherwise `anthropic/claude-opus-4-8`, matching the TS snapshot |
| OPENAI_API_KEY | Direct `openai/` models, such as `openai/gpt-4o-mini` |
| ANTHROPIC_API_KEY | Direct `anthropic/` models |
| GEMINI_API_KEY | Direct `google/` or `gemini/` models through Google's OpenAI-compatible endpoint |
| GOOGLE_GENERATIVE_AI_API_KEY | Fallback Google key; OpenAI keys are never used for direct Google requests |
| LLM_BASE_URL | Explicit OpenAI-compatible gateway; preserves the full model identifier |
| LLM_API_KEY | Preferred key for gateways and direct OpenAI; falls back to OPENAI_API_KEY |
| REDIS_URL | Required only for a nonempty `ledger` without an injected cost-ledger port |
| LLM_PRICING | JSON price overrides keyed by provider-prefixed model; values contain inputUsdPerMTok and optional outputUsdPerMTok |
| LLM_COST_LEDGER_TTL_SECONDS | TTL of at least one second; default 172800, rounded down |

The default model and estimated pricing table are copied from the pinned TS
snapshot, not a claim of current pricing or availability. Override `LLM_MODEL`
for your account. The example explicitly uses `openai/gpt-4o-mini`.

## Retries, usage, and cost tracking

Provider calls stream internally and assemble their text before returning JSON.
Direct OpenAI uses max_completion_tokens; gateways/Google use max_tokens.
Official SDK and HTTP retries are disabled; Render owns five retries with a
2000 ms base delay and 2x backoff. Clients close after each call.

Usage includes available input/output token counts and an estimated dollar cost
when known. Output accounting preserves the TS max(completion, total-prompt)
rule. Estimates ignore caching discounts and price tiers; they are not invoices.

A nonempty `ledger` appends a JSON cost record to Redis list `llm:cost:<ledger>`
with TTL, compatible with the TS format. Invalid ledger configuration fails
before provider spend. Pricing failures without a ledger and append/cleanup
failures after spend warn without failing the task, avoiding rebilling solely
to repair observability. Inject `CostLedgerPort` to use another store. The
default Redis adapter also disables client retries.
