Metadata-Version: 2.4
Name: anyask
Version: 0.1.0
Summary: Call an LLM provider, get its raw response back - one function, 17 vendors, zero routing/fallback magic
Author-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
Maintainer-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
License: MIT
Project-URL: Homepage, https://github.com/Geeks-Trident-LLC/anyask
Project-URL: Repository, https://github.com/Geeks-Trident-LLC/anyask
Project-URL: Issues, https://github.com/Geeks-Trident-LLC/anyask/issues
Keywords: ai,llm,openai,claude,anthropic,gemini,azure-ai-inference,deepseek,groq,xai,grok,together-ai,fireworks-ai,cerebras,perplexity,openrouter,moonshot,kimi,mistral,bedrock,aws,cohere,vertex ai,gcp,oracle cloud infrastructure,oci
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
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 :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == "openai"
Provides-Extra: deepseek
Requires-Dist: openai>=1.0.0; extra == "deepseek"
Provides-Extra: groq
Requires-Dist: openai>=1.0.0; extra == "groq"
Provides-Extra: xai
Requires-Dist: openai>=1.0.0; extra == "xai"
Provides-Extra: together
Requires-Dist: openai>=1.0.0; extra == "together"
Provides-Extra: fireworks
Requires-Dist: openai>=1.0.0; extra == "fireworks"
Provides-Extra: cerebras
Requires-Dist: openai>=1.0.0; extra == "cerebras"
Provides-Extra: perplexity
Requires-Dist: openai>=1.0.0; extra == "perplexity"
Provides-Extra: openrouter
Requires-Dist: openai>=1.0.0; extra == "openrouter"
Provides-Extra: moonshot
Requires-Dist: openai>=1.0.0; extra == "moonshot"
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.40.0; extra == "anthropic"
Provides-Extra: gemini
Requires-Dist: google-genai>=0.2.0; extra == "gemini"
Provides-Extra: vertexai
Requires-Dist: google-genai>=0.2.0; extra == "vertexai"
Provides-Extra: azure
Requires-Dist: azure-ai-inference>=1.0.0b9; extra == "azure"
Provides-Extra: mistral
Requires-Dist: mistralai==1.10.0; extra == "mistral"
Provides-Extra: bedrock
Requires-Dist: boto3==1.42.97; extra == "bedrock"
Provides-Extra: cohere
Requires-Dist: cohere==5.21.1; extra == "cohere"
Provides-Extra: oci
Requires-Dist: oci==2.182.0; extra == "oci"
Provides-Extra: all
Requires-Dist: openai>=1.0.0; extra == "all"
Requires-Dist: anthropic>=0.40.0; extra == "all"
Requires-Dist: google-genai>=0.2.0; extra == "all"
Requires-Dist: azure-ai-inference>=1.0.0b9; extra == "all"
Requires-Dist: mistralai==1.10.0; extra == "all"
Requires-Dist: boto3==1.42.97; extra == "all"
Requires-Dist: cohere==5.21.1; extra == "all"
Requires-Dist: oci==2.182.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
Requires-Dist: ruff>=0.4.0; extra == "dev"
Requires-Dist: black>=24.0.0; extra == "dev"
Requires-Dist: mypy>=1.10.0; extra == "dev"
Dynamic: license-file

# anyask

A single-responsibility Python package for one job: call an LLM provider, get its raw
response back. No routing, no fallback, no retries - you always name the provider and
model explicitly, and you always get the same normalized `AskResponse` shape back
regardless of which of the 17 supported vendors you called.

```python
import anyask

response = anyask.ask(
    "Say hello in one word.",
    provider="anthropic",
    model="claude-haiku-4-5-20251001",
    api_key="sk-...",  # or set ANTHROPIC_API_KEY
)

print(response.content)          # "Hello"
print(response.usage)            # TokenUsage(prompt_tokens=..., completion_tokens=..., total_tokens=...)
print(response.finish_reason)    # "end_turn" (raw, provider-specific - never normalized)
print(response.provider)         # "anthropic"
print(response.model)            # "claude-haiku-4-5-20251001"
```

## Documentation

Full documentation, including the [Providers](https://geeks-trident-llc.github.io/anyask/latest/providers/)
reference table, [Quickstart](https://geeks-trident-llc.github.io/anyask/latest/getting-started/quickstart/),
and generated [API Reference](https://geeks-trident-llc.github.io/anyask/latest/reference/),
is available at:

- **Latest docs:** [https://geeks-trident-llc.github.io/anyask/latest/](https://geeks-trident-llc.github.io/anyask/latest/)
- **All versions:** [https://geeks-trident-llc.github.io/anyask/](https://geeks-trident-llc.github.io/anyask/)

## Supported providers

`openai`, `anthropic`, `gemini`, `vertexai`, `azure`, `mistral`, `cohere`, `bedrock`,
`oci`, and the nine OpenAI-compatible vendors: `deepseek`, `groq`, `xai`, `together`,
`fireworks`, `cerebras`, `perplexity`, `openrouter`, `moonshot`.

## Install

A bare `pip install anyask` pulls in zero provider SDKs - only `PyYAML` (for the
built-in model catalog). Install the extra(s) for the provider(s) you actually use:

```bash
pip install anyask[anthropic]
pip install anyask[openai,gemini]
pip install anyask[all]       # every provider SDK
```

Provider SDK imports are lazy: resolving one provider by name never imports another
provider's SDK, so `import anyask` always succeeds even in an environment with no
provider SDKs installed at all.

## API

```python
def ask(prompt: str, *, provider: str, model: str, **kwargs) -> AskResponse: ...
async def ask_async(prompt: str, *, provider: str, model: str, **kwargs) -> AskResponse: ...
def list_models(provider: str, **kwargs) -> list[str]: ...
async def list_models_async(provider: str, **kwargs) -> list[str]: ...
def get_provider(provider: str, **config) -> Provider: ...
```

`**kwargs` passed to `ask`/`ask_async`/`list_models` is split automatically: construction
keys (`api_key`, `endpoint`, `api_version`, `deployment`, `region`, `project`,
`compartment_id`) go to the provider's constructor; everything else (`temperature`,
`max_tokens`, ...) is forwarded to the generation call unchanged. Any key a given
provider doesn't recognize is simply ignored, so the same kwargs dict can be handed to
any provider.

### `ask()` / `ask_async()`

```python
response = anyask.ask("What is 2+2?", provider="openai", model="gpt-4o-mini")

response = await anyask.ask_async(
    "What is 2+2?", provider="openai", model="gpt-4o-mini", temperature=0.0,
)
```

### `list_models()` / `list_models_async()`

```python
models = anyask.list_models("anthropic", api_key="sk-...")
# ['claude-opus-4-8', 'claude-sonnet-4-5', ...]
```

Raises `anyask.ProviderNotFoundError` if the resolved provider doesn't expose a live
model-listing endpoint (e.g. Perplexity returns a static list instead).

### `get_provider()` - reusable provider instances

`ask()` builds a fresh provider (and its underlying SDK client) on every call. If you're
making many calls against the same provider/credentials - e.g. resolving dozens of
prompts against one Anthropic API key in a loop - construct once and reuse:

```python
provider = anyask.get_provider("anthropic", api_key="sk-...")

for prompt in prompts:
    response = provider.generate_sync(prompt, model="claude-haiku-4-5-20251001")
```

This avoids rebuilding the SDK client (a fresh `boto3.client()`, re-reading
`~/.oci/config`, etc.) on every single call.

## Errors

```python
class AskLLMError(Exception): ...
class ProviderNotFoundError(AskLLMError): ...   # unknown provider name, or missing capability
class ProviderError(AskLLMError): ...            # provider call failed - raised with `from exc`
class ProviderAuthError(ProviderError): ...       # missing/invalid credentials at construction
```

Every provider call failure is raised as `ProviderError(...) from exc`, so
`err.__cause__` is always the original SDK exception - inspect it if you need
vendor-specific error details (status codes, error types, etc.).

## License

MIT
