@thinwrap/llm 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/cjs/base/base.connector.d.ts +44 -0
- package/dist/cjs/base/base.connector.js +216 -0
- package/dist/cjs/facades/chat.facade.d.ts +17 -0
- package/dist/cjs/facades/chat.facade.js +63 -0
- package/dist/cjs/facades/embeddings.facade.d.ts +23 -0
- package/dist/cjs/facades/embeddings.facade.js +63 -0
- package/dist/cjs/index.d.ts +15 -0
- package/dist/cjs/index.js +35 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/providers/_shared/openai-compat.connector.d.ts +23 -0
- package/dist/cjs/providers/_shared/openai-compat.connector.js +320 -0
- package/dist/cjs/providers/_shared/openai-compat.embeddings.connector.d.ts +18 -0
- package/dist/cjs/providers/_shared/openai-compat.embeddings.connector.js +105 -0
- package/dist/cjs/providers/_shared/spec.d.ts +99 -0
- package/dist/cjs/providers/_shared/spec.js +84 -0
- package/dist/cjs/providers/anthropic/anthropic.config.d.ts +17 -0
- package/dist/cjs/providers/anthropic/anthropic.config.js +2 -0
- package/dist/cjs/providers/anthropic/anthropic.connector.d.ts +30 -0
- package/dist/cjs/providers/anthropic/anthropic.connector.js +427 -0
- package/dist/cjs/providers/anthropic/index.d.ts +2 -0
- package/dist/cjs/providers/anthropic/index.js +5 -0
- package/dist/cjs/providers/bedrock/bedrock.config.d.ts +18 -0
- package/dist/cjs/providers/bedrock/bedrock.config.js +2 -0
- package/dist/cjs/providers/bedrock/bedrock.connector.d.ts +61 -0
- package/dist/cjs/providers/bedrock/bedrock.connector.js +479 -0
- package/dist/cjs/providers/bedrock/index.d.ts +2 -0
- package/dist/cjs/providers/bedrock/index.js +5 -0
- package/dist/cjs/providers/gemini/gemini.config.d.ts +12 -0
- package/dist/cjs/providers/gemini/gemini.config.js +2 -0
- package/dist/cjs/providers/gemini/gemini.connector.d.ts +28 -0
- package/dist/cjs/providers/gemini/gemini.connector.js +434 -0
- package/dist/cjs/providers/gemini/index.d.ts +2 -0
- package/dist/cjs/providers/gemini/index.js +5 -0
- package/dist/cjs/types/chat.types.d.ts +115 -0
- package/dist/cjs/types/chat.types.js +2 -0
- package/dist/cjs/types/config-map.type.d.ts +29 -0
- package/dist/cjs/types/config-map.type.js +2 -0
- package/dist/cjs/types/embeddings.types.d.ts +29 -0
- package/dist/cjs/types/embeddings.types.js +2 -0
- package/dist/cjs/types/error.types.d.ts +20 -0
- package/dist/cjs/types/error.types.js +22 -0
- package/dist/cjs/types/index.d.ts +7 -0
- package/dist/cjs/types/index.js +23 -0
- package/dist/cjs/types/passthrough.type.d.ts +15 -0
- package/dist/cjs/types/passthrough.type.js +2 -0
- package/dist/cjs/types/provider-id.enum.d.ts +8 -0
- package/dist/cjs/types/provider-id.enum.js +29 -0
- package/dist/cjs/types/provider.interface.d.ts +7 -0
- package/dist/cjs/types/provider.interface.js +2 -0
- package/dist/esm/base/base.connector.d.ts +44 -0
- package/dist/esm/base/base.connector.js +209 -0
- package/dist/esm/facades/chat.facade.d.ts +17 -0
- package/dist/esm/facades/chat.facade.js +59 -0
- package/dist/esm/facades/embeddings.facade.d.ts +23 -0
- package/dist/esm/facades/embeddings.facade.js +59 -0
- package/dist/esm/index.d.ts +15 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/providers/_shared/openai-compat.connector.d.ts +23 -0
- package/dist/esm/providers/_shared/openai-compat.connector.js +316 -0
- package/dist/esm/providers/_shared/openai-compat.embeddings.connector.d.ts +18 -0
- package/dist/esm/providers/_shared/openai-compat.embeddings.connector.js +101 -0
- package/dist/esm/providers/_shared/spec.d.ts +99 -0
- package/dist/esm/providers/_shared/spec.js +81 -0
- package/dist/esm/providers/anthropic/anthropic.config.d.ts +17 -0
- package/dist/esm/providers/anthropic/anthropic.config.js +1 -0
- package/dist/esm/providers/anthropic/anthropic.connector.d.ts +30 -0
- package/dist/esm/providers/anthropic/anthropic.connector.js +423 -0
- package/dist/esm/providers/anthropic/index.d.ts +2 -0
- package/dist/esm/providers/anthropic/index.js +1 -0
- package/dist/esm/providers/bedrock/bedrock.config.d.ts +18 -0
- package/dist/esm/providers/bedrock/bedrock.config.js +1 -0
- package/dist/esm/providers/bedrock/bedrock.connector.d.ts +61 -0
- package/dist/esm/providers/bedrock/bedrock.connector.js +474 -0
- package/dist/esm/providers/bedrock/index.d.ts +2 -0
- package/dist/esm/providers/bedrock/index.js +1 -0
- package/dist/esm/providers/gemini/gemini.config.d.ts +12 -0
- package/dist/esm/providers/gemini/gemini.config.js +1 -0
- package/dist/esm/providers/gemini/gemini.connector.d.ts +28 -0
- package/dist/esm/providers/gemini/gemini.connector.js +430 -0
- package/dist/esm/providers/gemini/index.d.ts +2 -0
- package/dist/esm/providers/gemini/index.js +1 -0
- package/dist/esm/types/chat.types.d.ts +115 -0
- package/dist/esm/types/chat.types.js +1 -0
- package/dist/esm/types/config-map.type.d.ts +29 -0
- package/dist/esm/types/config-map.type.js +1 -0
- package/dist/esm/types/embeddings.types.d.ts +29 -0
- package/dist/esm/types/embeddings.types.js +1 -0
- package/dist/esm/types/error.types.d.ts +20 -0
- package/dist/esm/types/error.types.js +18 -0
- package/dist/esm/types/index.d.ts +7 -0
- package/dist/esm/types/index.js +7 -0
- package/dist/esm/types/passthrough.type.d.ts +15 -0
- package/dist/esm/types/passthrough.type.js +1 -0
- package/dist/esm/types/provider-id.enum.d.ts +8 -0
- package/dist/esm/types/provider-id.enum.js +26 -0
- package/dist/esm/types/provider.interface.d.ts +7 -0
- package/dist/esm/types/provider.interface.js +1 -0
- package/package.json +73 -0
- package/src/providers/anthropic/README.md +64 -0
- package/src/providers/azure-openai/README.md +62 -0
- package/src/providers/bedrock/README.md +71 -0
- package/src/providers/cloudflare/README.md +62 -0
- package/src/providers/deepinfra/README.md +61 -0
- package/src/providers/deepseek/README.md +50 -0
- package/src/providers/fireworks/README.md +62 -0
- package/src/providers/gemini/README.md +67 -0
- package/src/providers/groq/README.md +50 -0
- package/src/providers/lmstudio/README.md +62 -0
- package/src/providers/mistral/README.md +61 -0
- package/src/providers/ollama/README.md +62 -0
- package/src/providers/openai/README.md +62 -0
- package/src/providers/openrouter/README.md +62 -0
- package/src/providers/perplexity/README.md +50 -0
- package/src/providers/together/README.md +61 -0
- package/src/providers/vllm/README.md +62 -0
- package/src/providers/xai/README.md +50 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Groq — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `groq` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('groq', { apiKey: process.env.GROQ_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'llama-3.3-70b-versatile',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | yes | — | Sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no | `https://api.groq.com/openai/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Create a key at <https://console.groq.com/keys>. It is sent as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST https://api.groq.com/openai/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- **Baseline-exception (handled):** in streaming, token usage is on `x_groq.usage` of the final chunk, not top-level `usage`. The connector relocates it so `ChatStreamDelta.usage` is populated the same as everywhere else (spec `streamUsagePath: 'x_groq'`).
|
|
39
|
+
- Strict JSON-schema structured output is limited to `openai/gpt-oss-*` models and can't combine with streaming or tools; other models are best-effort.
|
|
40
|
+
- Model ids are provider-namespaced (`openai/…`, `meta-llama/…`, `qwen/…`).
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
Groq exposes no OpenAI-float embeddings surface, so there is no `Embeddings` support — `new Embeddings('groq', …)` is a type error and throws `ConnectorError` (`invalid_request`).
|
|
45
|
+
|
|
46
|
+
## Error mapping & passthrough
|
|
47
|
+
|
|
48
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
49
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
50
|
+
- Rate-limit guidance: <https://console.groq.com/docs/rate-limits>.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# LM Studio (self-host) — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `lmstudio` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('lmstudio', {});
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: '<loaded-model>',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | no | — | Optional `Authorization: Bearer <apiKey>` (API-token auth since v0.4.0; off by default). |
|
|
22
|
+
| `baseUrl` | no | `http://localhost:1234/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Local single-user server; auth is off by default (leave `apiKey` empty → no auth header). If you enabled API-token auth, pass the token as `apiKey`; it is sent as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST http://localhost:1234/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- Self-host: local single-user server; override `baseUrl` if not on `:1234`.
|
|
39
|
+
- With a single model loaded, the server ignores the requested model id and serves whatever is loaded.
|
|
40
|
+
- Structured output is grammar-enforced (llama.cpp / MLX); small models can be unreliable.
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
Supported (served by the shared `OpenAICompatEmbeddingsConnector`).
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { Embeddings } from '@thinwrap/llm';
|
|
48
|
+
|
|
49
|
+
const emb = new Embeddings('lmstudio', {});
|
|
50
|
+
const out = await emb.create({
|
|
51
|
+
model: '<embedding-model>',
|
|
52
|
+
input: ['hello', 'world'],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`POST http://localhost:1234/v1/embeddings` with `encoding_format: 'float'`. `dimensions` maps to `dimensions` when set. Vectors are returned in input order on `out.embeddings`.
|
|
57
|
+
|
|
58
|
+
## Error mapping & passthrough
|
|
59
|
+
|
|
60
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
61
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
62
|
+
- Rate-limit guidance: <https://lmstudio.ai/docs/app/api>.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Mistral — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `mistral` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('mistral', { apiKey: process.env.MISTRAL_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'mistral-large-latest',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | yes | — | Sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no | `https://api.mistral.ai/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Create a key at <https://console.mistral.ai/api-keys>. It is sent as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST https://api.mistral.ai/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- **Baseline-exception (handled):** Mistral 422s on unknown params, so the connector omits OpenAI-only extras like `stream_options`. Keep `_passthrough.body` to known Mistral fields.
|
|
39
|
+
- Model ids are date-stamped (e.g. `-YYMM`).
|
|
40
|
+
|
|
41
|
+
## Embeddings
|
|
42
|
+
|
|
43
|
+
Supported (served by the shared `OpenAICompatEmbeddingsConnector`).
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { Embeddings } from '@thinwrap/llm';
|
|
47
|
+
|
|
48
|
+
const emb = new Embeddings('mistral', { apiKey: process.env.MISTRAL_API_KEY! });
|
|
49
|
+
const out = await emb.create({
|
|
50
|
+
model: 'mistral-embed',
|
|
51
|
+
input: ['hello', 'world'],
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`POST https://api.mistral.ai/v1/embeddings` with `encoding_format: 'float'`. `dimensions` maps to `dimensions` when set. Vectors are returned in input order on `out.embeddings`.
|
|
56
|
+
|
|
57
|
+
## Error mapping & passthrough
|
|
58
|
+
|
|
59
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
60
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
61
|
+
- Rate-limit guidance: <https://docs.mistral.ai/admin/user-management-finops/tier>.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Ollama (self-host) — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `ollama` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('ollama', {});
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'llama3.1:8b',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | no | — | None by default (local server); if set, sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no* | `http://localhost:11434/v1` | *Required for a non-default host. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
No auth by default — leave `apiKey` empty and no auth header is sent. Override `baseUrl` for a remote host.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST http://localhost:11434/v1/chat/completions` (override `baseUrl` for a non-default host).
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- Self-host: no auth by default; override `baseUrl` for a non-default host.
|
|
39
|
+
- Model ids are host-local `name:tag` (e.g. `llama3.1:8b`) — a 404 means the model isn't pulled (`ollama pull …`).
|
|
40
|
+
- The `/v1` compat layer is documented-partial (drops `tool_choice`/`logit_bias`/`n`; base64-only images).
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
Supported (served by the shared `OpenAICompatEmbeddingsConnector`).
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { Embeddings } from '@thinwrap/llm';
|
|
48
|
+
|
|
49
|
+
const emb = new Embeddings('ollama', {});
|
|
50
|
+
const out = await emb.create({
|
|
51
|
+
model: 'nomic-embed-text',
|
|
52
|
+
input: ['hello'],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`POST http://localhost:11434/v1/embeddings` with `encoding_format: 'float'`; `dimensions` maps to `dimensions` when set. Vectors are returned in input order on `out.embeddings`.
|
|
57
|
+
|
|
58
|
+
## Error mapping & passthrough
|
|
59
|
+
|
|
60
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
61
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
62
|
+
- Rate-limit guidance: <https://docs.ollama.com/api>.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# OpenAI — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `openai` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('openai', { apiKey: process.env.OPENAI_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'gpt-4o',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | yes | — | Sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no | `https://api.openai.com/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Create an API key at <https://platform.openai.com/api-keys>. It is sent verbatim as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST https://api.openai.com/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- The reference provider — its Chat Completions shape is the canonical facade shape.
|
|
39
|
+
- Reasoning models (o-series / GPT-5-class) reject `temperature`/`top_p`/penalties with a hard **HTTP 400** and require `max_completion_tokens` — guard by model family; don't blanket-pass sampling knobs.
|
|
40
|
+
- OpenAI also ships the newer **Responses API**; this connector targets Chat Completions (D1).
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
Supported (served by the shared `OpenAICompatEmbeddingsConnector`).
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { Embeddings } from '@thinwrap/llm';
|
|
48
|
+
|
|
49
|
+
const emb = new Embeddings('openai', { apiKey: process.env.OPENAI_API_KEY! });
|
|
50
|
+
const out = await emb.create({
|
|
51
|
+
model: 'text-embedding-3-small',
|
|
52
|
+
input: ['hello', 'world'],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`POST https://api.openai.com/v1/embeddings` with `encoding_format: 'float'`. `dimensions` maps to `dimensions` (Matryoshka) when set. Vectors are returned in input order on `out.embeddings`.
|
|
57
|
+
|
|
58
|
+
## Error mapping & passthrough
|
|
59
|
+
|
|
60
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
61
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
62
|
+
- Rate-limit guidance: <https://platform.openai.com/docs/guides/rate-limits>.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# OpenRouter — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `openrouter` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('openrouter', { apiKey: process.env.OPENROUTER_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'openai/gpt-4o',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | yes | — | Sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no | `https://openrouter.ai/api/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Create a key at <https://openrouter.ai/keys>. It is sent as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST https://openrouter.ai/api/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- Aggregator: model ids are `{provider}/{model}` (e.g. `anthropic/claude-sonnet-4.5`), with optional `:free`/`:nitro`/`:floor` suffixes.
|
|
39
|
+
- Pass `HTTP-Referer` / `X-Title` via `headers` for app attribution.
|
|
40
|
+
- Drops params an underlying provider lacks (unless `provider.require_parameters` is set via `_passthrough`); `n` is unsupported.
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
Supported (served by the shared `OpenAICompatEmbeddingsConnector`).
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { Embeddings } from '@thinwrap/llm';
|
|
48
|
+
|
|
49
|
+
const emb = new Embeddings('openrouter', { apiKey: process.env.OPENROUTER_API_KEY! });
|
|
50
|
+
const out = await emb.create({
|
|
51
|
+
model: 'openai/text-embedding-3-small',
|
|
52
|
+
input: ['hello', 'world'],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`POST https://openrouter.ai/api/v1/embeddings` with `encoding_format: 'float'`. `dimensions` maps to `dimensions` when set. Vectors are returned in input order on `out.embeddings`.
|
|
57
|
+
|
|
58
|
+
## Error mapping & passthrough
|
|
59
|
+
|
|
60
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
61
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
62
|
+
- Rate-limit guidance: <https://openrouter.ai/docs/api-reference/limits>.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Perplexity (Sonar) — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `perplexity` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('perplexity', { apiKey: process.env.PERPLEXITY_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'sonar',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | yes | — | Sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no | `https://api.perplexity.ai` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Create a key at <https://www.perplexity.ai/settings/api>. It is sent as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST https://api.perplexity.ai/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- **Baseline-exception (handled):** the Sonar chat surface has **no tool/function calling** (`tools` are not sent); tools live on Perplexity's separate Agent API.
|
|
39
|
+
- Sampling surface is stripped (no `top_k`/penalties/`seed`/`n` on Sonar).
|
|
40
|
+
- Model ids are `sonar` / `sonar-pro` / `sonar-reasoning-pro` / `sonar-deep-research`.
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
Perplexity exposes no OpenAI-float embeddings surface, so there is no `Embeddings` support — `new Embeddings('perplexity', …)` is a type error and throws `ConnectorError` (`invalid_request`).
|
|
45
|
+
|
|
46
|
+
## Error mapping & passthrough
|
|
47
|
+
|
|
48
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
49
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
50
|
+
- Rate-limit guidance: <https://docs.perplexity.ai/guides/usage-tiers>.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Together AI — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `together` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('together', { apiKey: process.env.TOGETHER_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'meta-llama/Llama-3.3-70B-Instruct-Turbo',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | yes | — | Sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no | `https://api.together.ai/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Create a key at <https://api.together.ai/settings/api-keys>. It is sent as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST https://api.together.ai/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- Model ids are namespaced `org/model` slugs — **OpenAI model strings like `gpt-4o` return 404**; use Together's ids.
|
|
39
|
+
- `service_tier`, `store`, `metadata`, `prediction`, and the vision `detail` field are accepted but ignored; `seed` is best-effort.
|
|
40
|
+
|
|
41
|
+
## Embeddings
|
|
42
|
+
|
|
43
|
+
Supported (served by the shared `OpenAICompatEmbeddingsConnector`).
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { Embeddings } from '@thinwrap/llm';
|
|
47
|
+
|
|
48
|
+
const emb = new Embeddings('together', { apiKey: process.env.TOGETHER_API_KEY! });
|
|
49
|
+
const out = await emb.create({
|
|
50
|
+
model: 'BAAI/bge-large-en-v1.5',
|
|
51
|
+
input: ['hello', 'world'],
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`POST https://api.together.ai/v1/embeddings` with `encoding_format: 'float'`. `dimensions` maps to `dimensions` when set. Vectors are returned in input order on `out.embeddings`.
|
|
56
|
+
|
|
57
|
+
## Error mapping & passthrough
|
|
58
|
+
|
|
59
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
60
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
61
|
+
- Rate-limit guidance: <https://docs.together.ai/docs/rate-limits>.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# vLLM (self-host) — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `vllm` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('vllm', { apiKey: process.env.VLLM_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: '<served-model-name>',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | no | — | Optional `Authorization: Bearer <apiKey>` (open if the server has no `--api-key`). |
|
|
22
|
+
| `baseUrl` | no | `http://localhost:8000/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Open by default. If the server was launched with `--api-key`, pass that value as `apiKey`; it is sent as `Authorization: Bearer <apiKey>`. When `apiKey` is empty, no auth header is sent.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST http://localhost:8000/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- Self-host: override `baseUrl` for a remote server; the compat server is vLLM's first-class interface.
|
|
39
|
+
- Model ids are operator-defined (the HF repo id or `--served-model-name`).
|
|
40
|
+
- `tool_choice: 'auto'` requires the server launched with `--enable-auto-tool-choice` + a model-matched `--tool-call-parser`.
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
Supported (served by the shared `OpenAICompatEmbeddingsConnector`).
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { Embeddings } from '@thinwrap/llm';
|
|
48
|
+
|
|
49
|
+
const emb = new Embeddings('vllm', { apiKey: process.env.VLLM_API_KEY! });
|
|
50
|
+
const out = await emb.create({
|
|
51
|
+
model: '<embedding-model>',
|
|
52
|
+
input: ['hello', 'world'],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`POST http://localhost:8000/v1/embeddings` with `encoding_format: 'float'`. `dimensions` maps to `dimensions` when set. Vectors are returned in input order on `out.embeddings`.
|
|
57
|
+
|
|
58
|
+
## Error mapping & passthrough
|
|
59
|
+
|
|
60
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
61
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
62
|
+
- Rate-limit guidance: <https://docs.vllm.ai/en/latest/serving/online_serving/openai_compatible_server/>.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# xAI (Grok) — `@thinwrap/llm`
|
|
2
|
+
|
|
3
|
+
First-class OpenAI-compatible provider — served by the shared `OpenAICompatConnector` via a row in `src/providers/_shared/spec.ts` (no per-provider connector class). It emits the identical normalized `ChatResult` / `ChatStreamDelta` / `ConnectorError` as every other connector, so switching to/from `xai` is just the provider id + `model`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Chat } from '@thinwrap/llm';
|
|
9
|
+
|
|
10
|
+
const chat = new Chat('xai', { apiKey: process.env.XAI_API_KEY! });
|
|
11
|
+
const res = await chat.complete({
|
|
12
|
+
model: 'grok-4',
|
|
13
|
+
messages: [{ role: 'user', content: 'Say hi in one word.' }],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
| Field | Required | Default | Notes |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `apiKey` | yes | — | Sent as `Authorization: Bearer <apiKey>`. |
|
|
22
|
+
| `baseUrl` | no | `https://api.x.ai/v1` | Override for proxies / gateways. |
|
|
23
|
+
| `fetch` | no | `globalThis.fetch` | Bring-your-own fetch. |
|
|
24
|
+
| `headers` | no | — | Extra headers merged onto every request. |
|
|
25
|
+
|
|
26
|
+
## Auth setup
|
|
27
|
+
|
|
28
|
+
Create a key at <https://console.x.ai>. It is sent as `Authorization: Bearer <apiKey>`.
|
|
29
|
+
|
|
30
|
+
## Chat
|
|
31
|
+
|
|
32
|
+
### Endpoint
|
|
33
|
+
|
|
34
|
+
`POST https://api.x.ai/v1/chat/completions`
|
|
35
|
+
|
|
36
|
+
### Notes / quirks
|
|
37
|
+
|
|
38
|
+
- Model ids are `grok-*`.
|
|
39
|
+
- xAI positions Chat Completions as a **legacy** endpoint (it steers new work to its own Responses API); this connector targets Chat Completions.
|
|
40
|
+
- In streaming, a tool/function call arrives **whole in a single chunk**, not as incremental argument deltas.
|
|
41
|
+
|
|
42
|
+
## Embeddings
|
|
43
|
+
|
|
44
|
+
xAI exposes no OpenAI-float embeddings surface, so there is no `Embeddings` support — `new Embeddings('xai', …)` is a type error and throws `ConnectorError` (`invalid_request`).
|
|
45
|
+
|
|
46
|
+
## Error mapping & passthrough
|
|
47
|
+
|
|
48
|
+
- Non-2xx responses throw `ConnectorError` with a 7-value `providerCode` (`auth_failed` / `rate_limited` / `provider_unavailable` / `invalid_request` / `context_length_exceeded` / `content_filtered` / `unknown`). The raw vendor body is on `cause.raw`; retry hints (when present) on `cause.retryAfter` / `cause.retryAfterSeconds`.
|
|
49
|
+
- Sub-baseline features — `topK`, `seed`, `frequency`/`presence_penalty`, `logitBias`, `n`, reasoning control beyond `reasoning.effort`, prompt caching — ride through `_passthrough` (request) / `raw` (result). They are never emulated.
|
|
50
|
+
- Rate-limit guidance: <https://docs.x.ai/docs/rate-limits>.
|