otari 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,57 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: astral-sh/setup-uv@v6
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+
23
+ - name: Install dependencies
24
+ run: uv sync --extra dev
25
+
26
+ - name: Lint
27
+ run: uv run ruff check .
28
+
29
+ - name: Type check
30
+ run: uv run mypy src/
31
+
32
+ - name: Test
33
+ run: uv run pytest
34
+
35
+ publish:
36
+ needs: test
37
+ runs-on: ubuntu-latest
38
+ environment: pypi
39
+ permissions:
40
+ contents: read
41
+ id-token: write
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+
45
+ - uses: astral-sh/setup-uv@v6
46
+
47
+ - name: Set version from release tag
48
+ run: |
49
+ VERSION="${GITHUB_REF_NAME#v}"
50
+ echo "Publishing version: $VERSION"
51
+ sed -i "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
52
+
53
+ - name: Build package
54
+ run: uv build
55
+
56
+ - name: Publish to PyPI
57
+ uses: pypa/gh-action-pypi-publish@release/v1
otari-0.0.1/.gitignore ADDED
@@ -0,0 +1,33 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg-info/
7
+ *.egg
8
+ dist/
9
+ build/
10
+ .eggs/
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # IDE
18
+ .idea/
19
+ .vscode/
20
+ *.swp
21
+ *.swo
22
+ *~
23
+
24
+ # Testing / Linting
25
+ .pytest_cache/
26
+ .coverage
27
+ htmlcov/
28
+ .mypy_cache/
29
+ .ruff_cache/
30
+
31
+ # OS
32
+ .DS_Store
33
+ Thumbs.db
otari-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,304 @@
1
+ Metadata-Version: 2.4
2
+ Name: otari
3
+ Version: 0.0.1
4
+ Summary: Python client for the otari gateway
5
+ Project-URL: Homepage, https://github.com/mozilla-ai/otari-sdk-python
6
+ Project-URL: Documentation, https://mozilla-ai.github.io/otari/
7
+ Project-URL: Repository, https://github.com/mozilla-ai/otari-sdk-python
8
+ Project-URL: Issues, https://github.com/mozilla-ai/otari-sdk-python/issues
9
+ Author-email: Mozilla AI <ai-engineering@mozilla.com>
10
+ License-Expression: Apache-2.0
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: httpx>=0.25.0
22
+ Requires-Dist: openai>=1.99.3
23
+ Provides-Extra: dev
24
+ Requires-Dist: mypy>=1.13; extra == 'dev'
25
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
26
+ Requires-Dist: pytest>=8.0; extra == 'dev'
27
+ Requires-Dist: ruff>=0.8; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ <p align="center">
31
+ <picture>
32
+ <img src="https://raw.githubusercontent.com/mozilla-ai/otari/refs/heads/main/docs/public/images/otari-logo-mark.png" width="20%" alt="Project logo"/>
33
+ </picture>
34
+ </p>
35
+
36
+ <div align="center">
37
+
38
+ # otari (Python)
39
+
40
+ ![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)
41
+ [![PyPI](https://img.shields.io/pypi/v/otari)](https://pypi.org/project/otari/)
42
+ <a href="https://discord.gg/4gf3zXrQUc">
43
+ <img src="https://img.shields.io/static/v1?label=Chat%20on&message=Discord&color=blue&logo=Discord&style=flat-square" alt="Discord">
44
+ </a>
45
+
46
+ **Python client for [otari-gateway](https://github.com/mozilla-ai/otari).**
47
+ Communicate with any LLM provider through the gateway using a single, typed interface.
48
+
49
+ [TypeScript SDK](https://github.com/mozilla-ai/otari-sdk-ts) | [Documentation](https://mozilla-ai.github.io/otari/) | [Platform (Beta)](https://otari.ai/)
50
+
51
+ </div>
52
+
53
+ ## Quickstart
54
+
55
+ ```python
56
+ from otari import OtariClient
57
+
58
+ client = OtariClient(
59
+ api_base="http://localhost:8000",
60
+ platform_token="your-token-here",
61
+ )
62
+
63
+ response = await client.completion(
64
+ model="openai:gpt-4o-mini",
65
+ messages=[{"role": "user", "content": "Hello!"}],
66
+ )
67
+
68
+ print(response.choices[0].message.content)
69
+ ```
70
+
71
+ **That's it!** Change the model string to switch between LLM providers through the gateway.
72
+
73
+ ## Installation
74
+
75
+ ### Requirements
76
+
77
+ - Python 3.11 or newer
78
+ - A running [otari-gateway](https://mozilla-ai.github.io/otari/gateway/overview/) instance
79
+
80
+ ### Install
81
+
82
+ ```bash
83
+ pip install otari
84
+ ```
85
+
86
+ ### Setting Up Credentials
87
+
88
+ Set environment variables for your gateway:
89
+
90
+ ```bash
91
+ export GATEWAY_API_BASE="http://localhost:8000"
92
+ export GATEWAY_PLATFORM_TOKEN="your-token-here"
93
+ # or for non-platform mode:
94
+ export GATEWAY_API_KEY="your-key-here"
95
+ ```
96
+
97
+ Alternatively, pass credentials directly when creating the client (see [Usage](#usage) examples).
98
+
99
+ ## otari-gateway
100
+
101
+ This Python SDK is a client for [otari-gateway](https://github.com/mozilla-ai/otari), an **optional** FastAPI-based proxy server that adds enterprise-grade features on top of the core library:
102
+
103
+ - **Budget Management** - Enforce spending limits with automatic daily, weekly, or monthly resets
104
+ - **API Key Management** - Issue, revoke, and monitor virtual API keys without exposing provider credentials
105
+ - **Usage Analytics** - Track every request with full token counts, costs, and metadata
106
+ - **Multi-tenant Support** - Manage access and budgets across users and teams
107
+
108
+ The gateway sits between your applications and LLM providers, exposing an OpenAI-compatible API that works with any supported provider.
109
+
110
+ ### Quick Start
111
+
112
+ ```bash
113
+ docker run \
114
+ -e GATEWAY_MASTER_KEY="your-secure-master-key" \
115
+ -e OPENAI_API_KEY="your-api-key" \
116
+ -p 8000:8000 \
117
+ ghcr.io/mozilla-ai/otari/gateway:latest
118
+ ```
119
+
120
+ > **Note:** You can use a specific release version instead of `latest` (e.g., `1.2.0`). See [available versions](https://github.com/orgs/mozilla-ai/packages/container/package/otari%2Fgateway).
121
+
122
+ ### Managed Platform (Beta)
123
+
124
+ Prefer a hosted experience? The [otari platform](https://otari.ai/) provides a managed control plane for keys, usage tracking, and cost visibility across providers, while still building on the same `otari` interfaces.
125
+
126
+ ## Usage
127
+
128
+ ### Authentication Modes
129
+
130
+ The client supports two authentication modes, matching the TypeScript SDK:
131
+
132
+ #### Platform Mode (Recommended)
133
+
134
+ Uses a Bearer token in the standard Authorization header:
135
+
136
+ ```python
137
+ client = OtariClient(
138
+ api_base="http://localhost:8000",
139
+ platform_token="tk_your_platform_token",
140
+ )
141
+ ```
142
+
143
+ #### Non-Platform Mode
144
+
145
+ Sends the API key via a custom `Otari-Key` header:
146
+
147
+ ```python
148
+ client = OtariClient(
149
+ api_base="http://localhost:8000",
150
+ api_key="your-api-key",
151
+ )
152
+ ```
153
+
154
+ #### Auto-Detection from Environment Variables
155
+
156
+ When no explicit credentials are provided, the client reads from environment variables:
157
+
158
+ ```python
159
+ # Uses GATEWAY_API_BASE, GATEWAY_PLATFORM_TOKEN, or GATEWAY_API_KEY
160
+ client = OtariClient()
161
+ ```
162
+
163
+ ### Chat Completions
164
+
165
+ ```python
166
+ response = await client.completion(
167
+ model="openai:gpt-4o-mini",
168
+ messages=[{"role": "user", "content": "Hello!"}],
169
+ )
170
+
171
+ print(response.choices[0].message.content)
172
+ ```
173
+
174
+ ### Streaming
175
+
176
+ ```python
177
+ stream = await client.completion(
178
+ model="openai:gpt-4o-mini",
179
+ messages=[{"role": "user", "content": "Tell me a story."}],
180
+ stream=True,
181
+ )
182
+
183
+ async for chunk in stream:
184
+ content = chunk.choices[0].delta.content
185
+ if content:
186
+ print(content, end="", flush=True)
187
+ ```
188
+
189
+ ### Responses API
190
+
191
+ ```python
192
+ response = await client.response(
193
+ model="openai:gpt-4o-mini",
194
+ input="Summarize this in one sentence.",
195
+ )
196
+
197
+ print(response.output_text)
198
+ ```
199
+
200
+ ### Embeddings
201
+
202
+ ```python
203
+ result = await client.embedding(
204
+ model="openai:text-embedding-3-small",
205
+ input="Hello world",
206
+ )
207
+
208
+ print(result.data[0].embedding)
209
+ ```
210
+
211
+ ### Listing Models
212
+
213
+ ```python
214
+ models = await client.list_models()
215
+ for model in models:
216
+ print(model.id)
217
+ ```
218
+
219
+ ### Error Handling
220
+
221
+ In platform mode, HTTP errors are mapped to typed exceptions:
222
+
223
+ ```python
224
+ from otari import OtariClient, AuthenticationError, RateLimitError
225
+
226
+ try:
227
+ response = await client.completion(
228
+ model="openai:gpt-4o-mini",
229
+ messages=[{"role": "user", "content": "Hello!"}],
230
+ )
231
+ except AuthenticationError as e:
232
+ print(f"Invalid credentials: {e.message}")
233
+ except RateLimitError as e:
234
+ print(f"Rate limited, retry after: {e.retry_after}")
235
+ ```
236
+
237
+ | HTTP Status | Error Class | Description |
238
+ |------------|-------------|-------------|
239
+ | 400 (capability) | `UnsupportedCapabilityError` | Selected provider does not support the requested capability |
240
+ | 401, 403 | `AuthenticationError` | Invalid or missing credentials |
241
+ | 402 | `InsufficientFundsError` | Budget or credits exhausted |
242
+ | 404 | `ModelNotFoundError` | Model not found or unavailable |
243
+ | 429 | `RateLimitError` | Rate limit exceeded (includes `retry_after`) |
244
+ | 502 | `UpstreamProviderError` | Upstream provider unreachable |
245
+ | 504 | `GatewayTimeoutError` | Gateway timed out waiting for provider |
246
+
247
+ `UnsupportedCapabilityError` surfaces in both platform and non-platform modes; the other mappings are platform-mode only.
248
+
249
+ ### Context Manager
250
+
251
+ The client supports async context manager for automatic cleanup:
252
+
253
+ ```python
254
+ async with OtariClient(api_base="http://localhost:8000") as client:
255
+ response = await client.completion(
256
+ model="openai:gpt-4o-mini",
257
+ messages=[{"role": "user", "content": "Hello!"}],
258
+ )
259
+ ```
260
+
261
+ ## Why choose `otari`?
262
+
263
+ - **Simple, unified interface** - Single client for all providers through the gateway, switch models with just a string change
264
+ - **Developer friendly** - Full type hints for better IDE support and clear, actionable error messages
265
+ - **Leverages the OpenAI SDK** - Built on the official OpenAI Python SDK for maximum compatibility
266
+ - **Async-first** - Built on `AsyncOpenAI` for modern async Python applications
267
+ - **Stays framework-agnostic** so it can be used across different projects and use cases
268
+ - **Battle-tested** - Powers our own production tools ([any-agent](https://github.com/mozilla-ai/any-agent))
269
+
270
+ ## Development
271
+
272
+ ```bash
273
+ # Create a virtual environment
274
+ python -m venv .venv
275
+ source .venv/bin/activate
276
+
277
+ # Install with dev dependencies
278
+ pip install -e ".[dev]"
279
+
280
+ # Run unit tests
281
+ pytest tests/
282
+
283
+ # Lint
284
+ ruff check src/ tests/
285
+
286
+ # Type-check
287
+ mypy src/
288
+ ```
289
+
290
+ ## Documentation
291
+
292
+ - **[Full Documentation](https://mozilla-ai.github.io/otari/)** - Complete guides and API reference
293
+ - **[Supported Providers](https://mozilla-ai.github.io/otari/providers/)** - List of all supported LLM providers
294
+ - **[Gateway Documentation](https://mozilla-ai.github.io/otari/gateway/overview/)** - Gateway setup and deployment
295
+ - **[TypeScript SDK](https://github.com/mozilla-ai/otari-sdk-ts)** - The TypeScript SDK for Node.js applications
296
+ - **[otari Platform (Beta)](https://otari.ai/)** - Hosted control plane for key management, usage tracking, and cost visibility
297
+
298
+ ## Contributing
299
+
300
+ We welcome contributions from developers of all skill levels! Please see the [Contributing Guide](https://github.com/mozilla-ai/otari/blob/main/CONTRIBUTING.md) or open an issue to discuss changes.
301
+
302
+ ## License
303
+
304
+ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
otari-0.0.1/README.md ADDED
@@ -0,0 +1,275 @@
1
+ <p align="center">
2
+ <picture>
3
+ <img src="https://raw.githubusercontent.com/mozilla-ai/otari/refs/heads/main/docs/public/images/otari-logo-mark.png" width="20%" alt="Project logo"/>
4
+ </picture>
5
+ </p>
6
+
7
+ <div align="center">
8
+
9
+ # otari (Python)
10
+
11
+ ![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)
12
+ [![PyPI](https://img.shields.io/pypi/v/otari)](https://pypi.org/project/otari/)
13
+ <a href="https://discord.gg/4gf3zXrQUc">
14
+ <img src="https://img.shields.io/static/v1?label=Chat%20on&message=Discord&color=blue&logo=Discord&style=flat-square" alt="Discord">
15
+ </a>
16
+
17
+ **Python client for [otari-gateway](https://github.com/mozilla-ai/otari).**
18
+ Communicate with any LLM provider through the gateway using a single, typed interface.
19
+
20
+ [TypeScript SDK](https://github.com/mozilla-ai/otari-sdk-ts) | [Documentation](https://mozilla-ai.github.io/otari/) | [Platform (Beta)](https://otari.ai/)
21
+
22
+ </div>
23
+
24
+ ## Quickstart
25
+
26
+ ```python
27
+ from otari import OtariClient
28
+
29
+ client = OtariClient(
30
+ api_base="http://localhost:8000",
31
+ platform_token="your-token-here",
32
+ )
33
+
34
+ response = await client.completion(
35
+ model="openai:gpt-4o-mini",
36
+ messages=[{"role": "user", "content": "Hello!"}],
37
+ )
38
+
39
+ print(response.choices[0].message.content)
40
+ ```
41
+
42
+ **That's it!** Change the model string to switch between LLM providers through the gateway.
43
+
44
+ ## Installation
45
+
46
+ ### Requirements
47
+
48
+ - Python 3.11 or newer
49
+ - A running [otari-gateway](https://mozilla-ai.github.io/otari/gateway/overview/) instance
50
+
51
+ ### Install
52
+
53
+ ```bash
54
+ pip install otari
55
+ ```
56
+
57
+ ### Setting Up Credentials
58
+
59
+ Set environment variables for your gateway:
60
+
61
+ ```bash
62
+ export GATEWAY_API_BASE="http://localhost:8000"
63
+ export GATEWAY_PLATFORM_TOKEN="your-token-here"
64
+ # or for non-platform mode:
65
+ export GATEWAY_API_KEY="your-key-here"
66
+ ```
67
+
68
+ Alternatively, pass credentials directly when creating the client (see [Usage](#usage) examples).
69
+
70
+ ## otari-gateway
71
+
72
+ This Python SDK is a client for [otari-gateway](https://github.com/mozilla-ai/otari), an **optional** FastAPI-based proxy server that adds enterprise-grade features on top of the core library:
73
+
74
+ - **Budget Management** - Enforce spending limits with automatic daily, weekly, or monthly resets
75
+ - **API Key Management** - Issue, revoke, and monitor virtual API keys without exposing provider credentials
76
+ - **Usage Analytics** - Track every request with full token counts, costs, and metadata
77
+ - **Multi-tenant Support** - Manage access and budgets across users and teams
78
+
79
+ The gateway sits between your applications and LLM providers, exposing an OpenAI-compatible API that works with any supported provider.
80
+
81
+ ### Quick Start
82
+
83
+ ```bash
84
+ docker run \
85
+ -e GATEWAY_MASTER_KEY="your-secure-master-key" \
86
+ -e OPENAI_API_KEY="your-api-key" \
87
+ -p 8000:8000 \
88
+ ghcr.io/mozilla-ai/otari/gateway:latest
89
+ ```
90
+
91
+ > **Note:** You can use a specific release version instead of `latest` (e.g., `1.2.0`). See [available versions](https://github.com/orgs/mozilla-ai/packages/container/package/otari%2Fgateway).
92
+
93
+ ### Managed Platform (Beta)
94
+
95
+ Prefer a hosted experience? The [otari platform](https://otari.ai/) provides a managed control plane for keys, usage tracking, and cost visibility across providers, while still building on the same `otari` interfaces.
96
+
97
+ ## Usage
98
+
99
+ ### Authentication Modes
100
+
101
+ The client supports two authentication modes, matching the TypeScript SDK:
102
+
103
+ #### Platform Mode (Recommended)
104
+
105
+ Uses a Bearer token in the standard Authorization header:
106
+
107
+ ```python
108
+ client = OtariClient(
109
+ api_base="http://localhost:8000",
110
+ platform_token="tk_your_platform_token",
111
+ )
112
+ ```
113
+
114
+ #### Non-Platform Mode
115
+
116
+ Sends the API key via a custom `Otari-Key` header:
117
+
118
+ ```python
119
+ client = OtariClient(
120
+ api_base="http://localhost:8000",
121
+ api_key="your-api-key",
122
+ )
123
+ ```
124
+
125
+ #### Auto-Detection from Environment Variables
126
+
127
+ When no explicit credentials are provided, the client reads from environment variables:
128
+
129
+ ```python
130
+ # Uses GATEWAY_API_BASE, GATEWAY_PLATFORM_TOKEN, or GATEWAY_API_KEY
131
+ client = OtariClient()
132
+ ```
133
+
134
+ ### Chat Completions
135
+
136
+ ```python
137
+ response = await client.completion(
138
+ model="openai:gpt-4o-mini",
139
+ messages=[{"role": "user", "content": "Hello!"}],
140
+ )
141
+
142
+ print(response.choices[0].message.content)
143
+ ```
144
+
145
+ ### Streaming
146
+
147
+ ```python
148
+ stream = await client.completion(
149
+ model="openai:gpt-4o-mini",
150
+ messages=[{"role": "user", "content": "Tell me a story."}],
151
+ stream=True,
152
+ )
153
+
154
+ async for chunk in stream:
155
+ content = chunk.choices[0].delta.content
156
+ if content:
157
+ print(content, end="", flush=True)
158
+ ```
159
+
160
+ ### Responses API
161
+
162
+ ```python
163
+ response = await client.response(
164
+ model="openai:gpt-4o-mini",
165
+ input="Summarize this in one sentence.",
166
+ )
167
+
168
+ print(response.output_text)
169
+ ```
170
+
171
+ ### Embeddings
172
+
173
+ ```python
174
+ result = await client.embedding(
175
+ model="openai:text-embedding-3-small",
176
+ input="Hello world",
177
+ )
178
+
179
+ print(result.data[0].embedding)
180
+ ```
181
+
182
+ ### Listing Models
183
+
184
+ ```python
185
+ models = await client.list_models()
186
+ for model in models:
187
+ print(model.id)
188
+ ```
189
+
190
+ ### Error Handling
191
+
192
+ In platform mode, HTTP errors are mapped to typed exceptions:
193
+
194
+ ```python
195
+ from otari import OtariClient, AuthenticationError, RateLimitError
196
+
197
+ try:
198
+ response = await client.completion(
199
+ model="openai:gpt-4o-mini",
200
+ messages=[{"role": "user", "content": "Hello!"}],
201
+ )
202
+ except AuthenticationError as e:
203
+ print(f"Invalid credentials: {e.message}")
204
+ except RateLimitError as e:
205
+ print(f"Rate limited, retry after: {e.retry_after}")
206
+ ```
207
+
208
+ | HTTP Status | Error Class | Description |
209
+ |------------|-------------|-------------|
210
+ | 400 (capability) | `UnsupportedCapabilityError` | Selected provider does not support the requested capability |
211
+ | 401, 403 | `AuthenticationError` | Invalid or missing credentials |
212
+ | 402 | `InsufficientFundsError` | Budget or credits exhausted |
213
+ | 404 | `ModelNotFoundError` | Model not found or unavailable |
214
+ | 429 | `RateLimitError` | Rate limit exceeded (includes `retry_after`) |
215
+ | 502 | `UpstreamProviderError` | Upstream provider unreachable |
216
+ | 504 | `GatewayTimeoutError` | Gateway timed out waiting for provider |
217
+
218
+ `UnsupportedCapabilityError` surfaces in both platform and non-platform modes; the other mappings are platform-mode only.
219
+
220
+ ### Context Manager
221
+
222
+ The client supports async context manager for automatic cleanup:
223
+
224
+ ```python
225
+ async with OtariClient(api_base="http://localhost:8000") as client:
226
+ response = await client.completion(
227
+ model="openai:gpt-4o-mini",
228
+ messages=[{"role": "user", "content": "Hello!"}],
229
+ )
230
+ ```
231
+
232
+ ## Why choose `otari`?
233
+
234
+ - **Simple, unified interface** - Single client for all providers through the gateway, switch models with just a string change
235
+ - **Developer friendly** - Full type hints for better IDE support and clear, actionable error messages
236
+ - **Leverages the OpenAI SDK** - Built on the official OpenAI Python SDK for maximum compatibility
237
+ - **Async-first** - Built on `AsyncOpenAI` for modern async Python applications
238
+ - **Stays framework-agnostic** so it can be used across different projects and use cases
239
+ - **Battle-tested** - Powers our own production tools ([any-agent](https://github.com/mozilla-ai/any-agent))
240
+
241
+ ## Development
242
+
243
+ ```bash
244
+ # Create a virtual environment
245
+ python -m venv .venv
246
+ source .venv/bin/activate
247
+
248
+ # Install with dev dependencies
249
+ pip install -e ".[dev]"
250
+
251
+ # Run unit tests
252
+ pytest tests/
253
+
254
+ # Lint
255
+ ruff check src/ tests/
256
+
257
+ # Type-check
258
+ mypy src/
259
+ ```
260
+
261
+ ## Documentation
262
+
263
+ - **[Full Documentation](https://mozilla-ai.github.io/otari/)** - Complete guides and API reference
264
+ - **[Supported Providers](https://mozilla-ai.github.io/otari/providers/)** - List of all supported LLM providers
265
+ - **[Gateway Documentation](https://mozilla-ai.github.io/otari/gateway/overview/)** - Gateway setup and deployment
266
+ - **[TypeScript SDK](https://github.com/mozilla-ai/otari-sdk-ts)** - The TypeScript SDK for Node.js applications
267
+ - **[otari Platform (Beta)](https://otari.ai/)** - Hosted control plane for key management, usage tracking, and cost visibility
268
+
269
+ ## Contributing
270
+
271
+ We welcome contributions from developers of all skill levels! Please see the [Contributing Guide](https://github.com/mozilla-ai/otari/blob/main/CONTRIBUTING.md) or open an issue to discuss changes.
272
+
273
+ ## License
274
+
275
+ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.