swarmauri_llm_xai 0.11.0.dev4__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.
- swarmauri_llm_xai-0.11.0.dev4/PKG-INFO +92 -0
- swarmauri_llm_xai-0.11.0.dev4/README.md +69 -0
- swarmauri_llm_xai-0.11.0.dev4/pyproject.toml +54 -0
- swarmauri_llm_xai-0.11.0.dev4/swarmauri_llm_xai/XAIChatRetryPolicy.py +34 -0
- swarmauri_llm_xai-0.11.0.dev4/swarmauri_llm_xai/XAIModel.py +104 -0
- swarmauri_llm_xai-0.11.0.dev4/swarmauri_llm_xai/XAIToolModel.py +111 -0
- swarmauri_llm_xai-0.11.0.dev4/swarmauri_llm_xai/__init__.py +12 -0
- swarmauri_llm_xai-0.11.0.dev4/swarmauri_llm_xai/_client.py +27 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: swarmauri_llm_xai
|
|
3
|
+
Version: 0.11.0.dev4
|
|
4
|
+
Summary: Provider-native Swarmauri chat and tool-calling adapters for the xAI Inference API.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Keywords: swarmauri,llm,xai,grok,tool calling,streaming,inference api
|
|
7
|
+
Author: Jacob Stewart
|
|
8
|
+
Author-email: jacob@swarmauri.com
|
|
9
|
+
Requires-Python: >=3.10,<3.13
|
|
10
|
+
Classifier: Development Status :: 1 - Planning
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: swarmauri_base (>=0.11.0.dev5)
|
|
16
|
+
Requires-Dist: swarmauri_core (>=0.11.0.dev5)
|
|
17
|
+
Requires-Dist: swarmauri_provider_xai (>=0.1.0.dev3)
|
|
18
|
+
Requires-Dist: swarmauri_standard (>=0.11.0.dev6)
|
|
19
|
+
Requires-Dist: swarmauri_transport_httpx (>=0.1.0.dev5)
|
|
20
|
+
Requires-Dist: swarmauri_transport_retry (>=0.1.0.dev1)
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
<a href="https://pepy.tech/project/swarmauri_llm_xai"><img src="https://static.pepy.tech/badge/swarmauri_llm_xai/month" alt="Downloads"></a>
|
|
27
|
+
<a href="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/community/swarmauri_llm_xai/"><img src="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/community/swarmauri_llm_xai.svg" alt="Hits"></a>
|
|
28
|
+
<a href="https://pypi.org/project/swarmauri_llm_xai/"><img src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue" alt="Python"></a>
|
|
29
|
+
<a href="https://pypi.org/project/swarmauri_llm_xai/"><img src="https://img.shields.io/pypi/l/swarmauri_llm_xai" alt="License"></a>
|
|
30
|
+
<a href="https://pypi.org/project/swarmauri_llm_xai/"><img src="https://img.shields.io/pypi/v/swarmauri_llm_xai" alt="Release"></a>
|
|
31
|
+
</p>
|
|
32
|
+
|
|
33
|
+
# Swarmauri xAI LLM
|
|
34
|
+
|
|
35
|
+
`swarmauri_llm_xai` provides provider-native Swarmauri adapters for xAI's Grok chat-completions API.
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- `XAIModel` directly implements the Swarmauri LLM base contract.
|
|
40
|
+
- `XAIToolModel` directly implements the tool-LLM base contract.
|
|
41
|
+
- Bearer-token authentication with credentials excluded from serialized state.
|
|
42
|
+
- Sync, async, incremental streaming, batch, and function-calling workflows.
|
|
43
|
+
- Optional model discovery through xAI's language-model catalog.
|
|
44
|
+
- Explicit provider, HTTP client, and retry-policy composition.
|
|
45
|
+
- Conservative chat retries that do not replay ambiguous connection failures.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv add swarmauri_llm_xai
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install swarmauri_llm_xai
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import os
|
|
61
|
+
|
|
62
|
+
from swarmauri_llm_xai import XAIModel
|
|
63
|
+
from swarmauri_standard.conversations.Conversation import Conversation
|
|
64
|
+
from swarmauri_standard.messages.HumanMessage import HumanMessage
|
|
65
|
+
|
|
66
|
+
conversation = Conversation(
|
|
67
|
+
messages=[HumanMessage(content="Explain orbital mechanics briefly.")]
|
|
68
|
+
)
|
|
69
|
+
model = XAIModel(api_key=os.environ["XAI_API_KEY"], name="grok-4.3")
|
|
70
|
+
model.predict(conversation)
|
|
71
|
+
print(conversation.get_last().content)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
For explicit composition:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from swarmauri_llm_xai import XAIChatRetryPolicy, XAIModel
|
|
78
|
+
from swarmauri_provider_xai import XAIProvider
|
|
79
|
+
from swarmauri_transport_httpx import HttpxClient
|
|
80
|
+
|
|
81
|
+
provider = XAIProvider(api_key=os.environ["XAI_API_KEY"])
|
|
82
|
+
model = XAIModel(
|
|
83
|
+
provider=provider,
|
|
84
|
+
http_client=HttpxClient(base_url=provider.base_url),
|
|
85
|
+
retry_policy=XAIChatRetryPolicy(max_attempts=3),
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Use `XAIToolModel` with a Swarmauri `Toolkit` for function calling. Set `discover_models=True` to populate allowed model IDs from the authenticated xAI language-model catalog.
|
|
90
|
+
|
|
91
|
+
See the [xAI inference reference](https://docs.x.ai/developers/rest-api-reference/inference), [chat endpoint](https://docs.x.ai/developers/rest-api-reference/inference/chat), and [function-calling guide](https://docs.x.ai/developers/tools/function-calling).
|
|
92
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://pepy.tech/project/swarmauri_llm_xai"><img src="https://static.pepy.tech/badge/swarmauri_llm_xai/month" alt="Downloads"></a>
|
|
5
|
+
<a href="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/community/swarmauri_llm_xai/"><img src="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/community/swarmauri_llm_xai.svg" alt="Hits"></a>
|
|
6
|
+
<a href="https://pypi.org/project/swarmauri_llm_xai/"><img src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue" alt="Python"></a>
|
|
7
|
+
<a href="https://pypi.org/project/swarmauri_llm_xai/"><img src="https://img.shields.io/pypi/l/swarmauri_llm_xai" alt="License"></a>
|
|
8
|
+
<a href="https://pypi.org/project/swarmauri_llm_xai/"><img src="https://img.shields.io/pypi/v/swarmauri_llm_xai" alt="Release"></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
# Swarmauri xAI LLM
|
|
12
|
+
|
|
13
|
+
`swarmauri_llm_xai` provides provider-native Swarmauri adapters for xAI's Grok chat-completions API.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- `XAIModel` directly implements the Swarmauri LLM base contract.
|
|
18
|
+
- `XAIToolModel` directly implements the tool-LLM base contract.
|
|
19
|
+
- Bearer-token authentication with credentials excluded from serialized state.
|
|
20
|
+
- Sync, async, incremental streaming, batch, and function-calling workflows.
|
|
21
|
+
- Optional model discovery through xAI's language-model catalog.
|
|
22
|
+
- Explicit provider, HTTP client, and retry-policy composition.
|
|
23
|
+
- Conservative chat retries that do not replay ambiguous connection failures.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv add swarmauri_llm_xai
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install swarmauri_llm_xai
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import os
|
|
39
|
+
|
|
40
|
+
from swarmauri_llm_xai import XAIModel
|
|
41
|
+
from swarmauri_standard.conversations.Conversation import Conversation
|
|
42
|
+
from swarmauri_standard.messages.HumanMessage import HumanMessage
|
|
43
|
+
|
|
44
|
+
conversation = Conversation(
|
|
45
|
+
messages=[HumanMessage(content="Explain orbital mechanics briefly.")]
|
|
46
|
+
)
|
|
47
|
+
model = XAIModel(api_key=os.environ["XAI_API_KEY"], name="grok-4.3")
|
|
48
|
+
model.predict(conversation)
|
|
49
|
+
print(conversation.get_last().content)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For explicit composition:
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from swarmauri_llm_xai import XAIChatRetryPolicy, XAIModel
|
|
56
|
+
from swarmauri_provider_xai import XAIProvider
|
|
57
|
+
from swarmauri_transport_httpx import HttpxClient
|
|
58
|
+
|
|
59
|
+
provider = XAIProvider(api_key=os.environ["XAI_API_KEY"])
|
|
60
|
+
model = XAIModel(
|
|
61
|
+
provider=provider,
|
|
62
|
+
http_client=HttpxClient(base_url=provider.base_url),
|
|
63
|
+
retry_policy=XAIChatRetryPolicy(max_attempts=3),
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Use `XAIToolModel` with a Swarmauri `Toolkit` for function calling. Set `discover_models=True` to populate allowed model IDs from the authenticated xAI language-model catalog.
|
|
68
|
+
|
|
69
|
+
See the [xAI inference reference](https://docs.x.ai/developers/rest-api-reference/inference), [chat endpoint](https://docs.x.ai/developers/rest-api-reference/inference/chat), and [function-calling guide](https://docs.x.ai/developers/tools/function-calling).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "swarmauri_llm_xai"
|
|
3
|
+
version = "0.11.0.dev4"
|
|
4
|
+
description = "Provider-native Swarmauri chat and tool-calling adapters for the xAI Inference API."
|
|
5
|
+
license = "Apache-2.0"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.10,<3.13"
|
|
8
|
+
authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
|
|
9
|
+
keywords = ["swarmauri", "llm", "xai", "grok", "tool calling", "streaming", "inference api"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 1 - Planning",
|
|
12
|
+
"License :: OSI Approved :: Apache Software License",
|
|
13
|
+
"Programming Language :: Python :: 3.10",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
]
|
|
17
|
+
dependencies = [
|
|
18
|
+
"swarmauri_base>=0.11.0.dev5",
|
|
19
|
+
"swarmauri_core>=0.11.0.dev5",
|
|
20
|
+
"swarmauri_provider_xai>=0.1.0.dev3",
|
|
21
|
+
"swarmauri_standard>=0.11.0.dev6",
|
|
22
|
+
"swarmauri_transport_httpx>=0.1.0.dev5",
|
|
23
|
+
"swarmauri_transport_retry>=0.1.0.dev1",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[tool.uv.sources]
|
|
27
|
+
swarmauri_base = { workspace = true }
|
|
28
|
+
swarmauri_core = { workspace = true }
|
|
29
|
+
swarmauri_provider_xai = { workspace = true }
|
|
30
|
+
swarmauri_standard = { workspace = true }
|
|
31
|
+
swarmauri_transport_httpx = { workspace = true }
|
|
32
|
+
swarmauri_transport_retry = { workspace = true }
|
|
33
|
+
|
|
34
|
+
[project.entry-points."swarmauri.llms"]
|
|
35
|
+
XAIModel = "swarmauri_llm_xai:XAIModel"
|
|
36
|
+
|
|
37
|
+
[project.entry-points."swarmauri.tool_llms"]
|
|
38
|
+
XAIToolModel = "swarmauri_llm_xai:XAIToolModel"
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["poetry-core>=1.0.0"]
|
|
42
|
+
build-backend = "poetry.core.masonry.api"
|
|
43
|
+
|
|
44
|
+
[dependency-groups]
|
|
45
|
+
dev = ["pytest>=8.0", "pytest-asyncio>=0.24", "ruff>=0.9.9"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
markers = ["unit: Unit tests"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff]
|
|
51
|
+
extend = "../../pyproject.toml"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
ignore = ["N999"]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Replay policy for xAI chat and model-discovery operations."""
|
|
2
|
+
|
|
3
|
+
from swarmauri_core.transports.i_http_response import IHttpResponse
|
|
4
|
+
from swarmauri_transport_retry import ExponentialBackoffRetryPolicy
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class XAIChatRetryPolicy(ExponentialBackoffRetryPolicy):
|
|
8
|
+
"""Retry xAI reads broadly and chat writes conservatively."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, **kwargs) -> None:
|
|
11
|
+
kwargs.setdefault("retryable_methods", {"GET", "POST"})
|
|
12
|
+
super().__init__(**kwargs)
|
|
13
|
+
|
|
14
|
+
def should_retry(
|
|
15
|
+
self,
|
|
16
|
+
*,
|
|
17
|
+
method: str,
|
|
18
|
+
attempt: int,
|
|
19
|
+
response: IHttpResponse | None = None,
|
|
20
|
+
error: Exception | None = None,
|
|
21
|
+
) -> bool:
|
|
22
|
+
if method.upper() == "POST":
|
|
23
|
+
return (
|
|
24
|
+
attempt < self.max_attempts
|
|
25
|
+
and error is None
|
|
26
|
+
and response is not None
|
|
27
|
+
and response.status_code == 429
|
|
28
|
+
)
|
|
29
|
+
return super().should_retry(
|
|
30
|
+
method=method,
|
|
31
|
+
attempt=attempt,
|
|
32
|
+
response=response,
|
|
33
|
+
error=error,
|
|
34
|
+
)
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from typing import Any, ClassVar, Literal
|
|
2
|
+
|
|
3
|
+
from pydantic import PrivateAttr
|
|
4
|
+
from swarmauri_base.ComponentBase import ComponentBase
|
|
5
|
+
from swarmauri_base.llms.LLMBase import LLMBase
|
|
6
|
+
from swarmauri_core.transports.i_http_client import IHttpClient
|
|
7
|
+
from swarmauri_core.transports.i_http_retry_policy import IHttpRetryPolicy
|
|
8
|
+
from swarmauri_provider_xai import XAIProvider
|
|
9
|
+
from swarmauri_standard.utils.provider_chat_transport import (
|
|
10
|
+
abatch_chat,
|
|
11
|
+
apredict_chat,
|
|
12
|
+
astream_chat,
|
|
13
|
+
batch_chat,
|
|
14
|
+
predict_chat,
|
|
15
|
+
stream_chat,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from ._client import build_xai_client
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@ComponentBase.register_type()
|
|
22
|
+
class XAIModel(LLMBase):
|
|
23
|
+
"""Provider-native xAI chat-completions model."""
|
|
24
|
+
|
|
25
|
+
type: Literal["XAIModel"] = "XAIModel"
|
|
26
|
+
base_url: str = "https://api.x.ai/v1"
|
|
27
|
+
name: str = "grok-4.3"
|
|
28
|
+
discover_models: bool = False
|
|
29
|
+
capabilities: ClassVar[frozenset[str]] = frozenset(
|
|
30
|
+
{"chat_completions", "multimodal_input", "streaming", "tools"}
|
|
31
|
+
)
|
|
32
|
+
_provider: XAIProvider = PrivateAttr()
|
|
33
|
+
_http_client: IHttpClient = PrivateAttr()
|
|
34
|
+
_retry_owned_by_transport: bool = PrivateAttr(default=True)
|
|
35
|
+
|
|
36
|
+
predict = predict_chat
|
|
37
|
+
apredict = apredict_chat
|
|
38
|
+
stream = stream_chat
|
|
39
|
+
astream = astream_chat
|
|
40
|
+
batch = batch_chat
|
|
41
|
+
abatch = abatch_chat
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
*,
|
|
46
|
+
provider: XAIProvider | None = None,
|
|
47
|
+
http_client: IHttpClient | None = None,
|
|
48
|
+
retry_policy: IHttpRetryPolicy | None = None,
|
|
49
|
+
**data: Any,
|
|
50
|
+
) -> None:
|
|
51
|
+
selected_name = data.get(
|
|
52
|
+
"name", self.__class__.model_fields["name"].default
|
|
53
|
+
)
|
|
54
|
+
data.setdefault("allowed_models", [selected_name])
|
|
55
|
+
super().__init__(**data)
|
|
56
|
+
if self.api_key is None:
|
|
57
|
+
if provider is None or provider.api_key is None:
|
|
58
|
+
raise ValueError(
|
|
59
|
+
"api_key or an authenticated provider is required"
|
|
60
|
+
)
|
|
61
|
+
self._provider = provider or XAIProvider(
|
|
62
|
+
api_key=self.api_key,
|
|
63
|
+
base_url=self.base_url,
|
|
64
|
+
timeout=self.timeout,
|
|
65
|
+
max_retries=self.max_retries,
|
|
66
|
+
)
|
|
67
|
+
self.base_url = self._provider.base_url or self.base_url
|
|
68
|
+
self._http_client = build_xai_client(
|
|
69
|
+
provider=self._provider,
|
|
70
|
+
http_client=http_client,
|
|
71
|
+
retry_policy=retry_policy,
|
|
72
|
+
)
|
|
73
|
+
if self.discover_models:
|
|
74
|
+
self.allowed_models = self._get_models()
|
|
75
|
+
elif not self.allowed_models:
|
|
76
|
+
self.allowed_models = [self.name]
|
|
77
|
+
|
|
78
|
+
def _build_endpoint(self) -> str:
|
|
79
|
+
config = self._provider.connection_config(
|
|
80
|
+
"chat.completions", model=self.name
|
|
81
|
+
)
|
|
82
|
+
return str(config.endpoint)
|
|
83
|
+
|
|
84
|
+
def _build_headers(self) -> dict[str, str]:
|
|
85
|
+
config = self._provider.connection_config(
|
|
86
|
+
"chat.completions", model=self.name
|
|
87
|
+
)
|
|
88
|
+
return self._provider.authorize(config)
|
|
89
|
+
|
|
90
|
+
def _get_models(self) -> list[str]:
|
|
91
|
+
if not self.discover_models:
|
|
92
|
+
return [self.name]
|
|
93
|
+
config = self._provider.connection_config("models.list")
|
|
94
|
+
response = self._http_client.request(
|
|
95
|
+
"GET",
|
|
96
|
+
str(config.endpoint),
|
|
97
|
+
headers=self._provider.authorize(config),
|
|
98
|
+
)
|
|
99
|
+
response.raise_for_status()
|
|
100
|
+
return [
|
|
101
|
+
item["id"]
|
|
102
|
+
for item in response.json().get("models", [])
|
|
103
|
+
if item.get("id")
|
|
104
|
+
]
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from typing import Any, ClassVar, Literal
|
|
2
|
+
|
|
3
|
+
from pydantic import PrivateAttr
|
|
4
|
+
from swarmauri_base.ComponentBase import ComponentBase
|
|
5
|
+
from swarmauri_base.tool_llms.ToolLLMBase import ToolLLMBase
|
|
6
|
+
from swarmauri_core.transports.i_http_client import IHttpClient
|
|
7
|
+
from swarmauri_core.transports.i_http_retry_policy import IHttpRetryPolicy
|
|
8
|
+
from swarmauri_provider_xai import XAIProvider, XAIToolSchemaConverter
|
|
9
|
+
from swarmauri_standard.utils.provider_chat_transport import (
|
|
10
|
+
abatch_tools,
|
|
11
|
+
apredict_tools,
|
|
12
|
+
astream_tools,
|
|
13
|
+
batch_tools,
|
|
14
|
+
format_messages,
|
|
15
|
+
predict_tools,
|
|
16
|
+
stream_tools,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from ._client import build_xai_client
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@ComponentBase.register_type()
|
|
23
|
+
class XAIToolModel(ToolLLMBase):
|
|
24
|
+
"""Provider-native xAI tool-calling model."""
|
|
25
|
+
|
|
26
|
+
type: Literal["XAIToolModel"] = "XAIToolModel"
|
|
27
|
+
base_url: str = "https://api.x.ai/v1"
|
|
28
|
+
name: str = "grok-4.3"
|
|
29
|
+
discover_models: bool = False
|
|
30
|
+
capabilities: ClassVar[frozenset[str]] = frozenset(
|
|
31
|
+
{"chat_completions", "streaming", "tools"}
|
|
32
|
+
)
|
|
33
|
+
_provider: XAIProvider = PrivateAttr()
|
|
34
|
+
_http_client: IHttpClient = PrivateAttr()
|
|
35
|
+
_retry_owned_by_transport: bool = PrivateAttr(default=True)
|
|
36
|
+
|
|
37
|
+
predict = predict_tools
|
|
38
|
+
apredict = apredict_tools
|
|
39
|
+
stream = stream_tools
|
|
40
|
+
astream = astream_tools
|
|
41
|
+
batch = batch_tools
|
|
42
|
+
abatch = abatch_tools
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
*,
|
|
47
|
+
provider: XAIProvider | None = None,
|
|
48
|
+
http_client: IHttpClient | None = None,
|
|
49
|
+
retry_policy: IHttpRetryPolicy | None = None,
|
|
50
|
+
**data: Any,
|
|
51
|
+
) -> None:
|
|
52
|
+
selected_name = data.get(
|
|
53
|
+
"name", self.__class__.model_fields["name"].default
|
|
54
|
+
)
|
|
55
|
+
data.setdefault("allowed_models", [selected_name])
|
|
56
|
+
super().__init__(**data)
|
|
57
|
+
if self.api_key is None:
|
|
58
|
+
if provider is None or provider.api_key is None:
|
|
59
|
+
raise ValueError(
|
|
60
|
+
"api_key or an authenticated provider is required"
|
|
61
|
+
)
|
|
62
|
+
self._provider = provider or XAIProvider(
|
|
63
|
+
api_key=self.api_key,
|
|
64
|
+
base_url=self.base_url,
|
|
65
|
+
timeout=self.timeout,
|
|
66
|
+
max_retries=self.max_retries,
|
|
67
|
+
)
|
|
68
|
+
self.base_url = self._provider.base_url or self.base_url
|
|
69
|
+
self._http_client = build_xai_client(
|
|
70
|
+
provider=self._provider,
|
|
71
|
+
http_client=http_client,
|
|
72
|
+
retry_policy=retry_policy,
|
|
73
|
+
)
|
|
74
|
+
if self.discover_models:
|
|
75
|
+
self.allowed_models = self._get_models()
|
|
76
|
+
elif not self.allowed_models:
|
|
77
|
+
self.allowed_models = [self.name]
|
|
78
|
+
|
|
79
|
+
def get_schema_converter(self):
|
|
80
|
+
return XAIToolSchemaConverter()
|
|
81
|
+
|
|
82
|
+
def _format_messages(self, messages):
|
|
83
|
+
return format_messages(messages)
|
|
84
|
+
|
|
85
|
+
def _build_endpoint(self) -> str:
|
|
86
|
+
config = self._provider.connection_config(
|
|
87
|
+
"chat.completions", model=self.name
|
|
88
|
+
)
|
|
89
|
+
return str(config.endpoint)
|
|
90
|
+
|
|
91
|
+
def _build_headers(self) -> dict[str, str]:
|
|
92
|
+
config = self._provider.connection_config(
|
|
93
|
+
"chat.completions", model=self.name
|
|
94
|
+
)
|
|
95
|
+
return self._provider.authorize(config)
|
|
96
|
+
|
|
97
|
+
def _get_models(self) -> list[str]:
|
|
98
|
+
if not self.discover_models:
|
|
99
|
+
return [self.name]
|
|
100
|
+
config = self._provider.connection_config("models.list")
|
|
101
|
+
response = self._http_client.request(
|
|
102
|
+
"GET",
|
|
103
|
+
str(config.endpoint),
|
|
104
|
+
headers=self._provider.authorize(config),
|
|
105
|
+
)
|
|
106
|
+
response.raise_for_status()
|
|
107
|
+
return [
|
|
108
|
+
item["id"]
|
|
109
|
+
for item in response.json().get("models", [])
|
|
110
|
+
if item.get("id")
|
|
111
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
|
+
|
|
3
|
+
from .XAIModel import XAIModel
|
|
4
|
+
from .XAIChatRetryPolicy import XAIChatRetryPolicy
|
|
5
|
+
from .XAIToolModel import XAIToolModel
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
__version__ = version("swarmauri_llm_xai")
|
|
9
|
+
except PackageNotFoundError:
|
|
10
|
+
__version__ = "0.0.0"
|
|
11
|
+
|
|
12
|
+
__all__ = ["XAIChatRetryPolicy", "XAIModel", "XAIToolModel"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Client composition for xAI model families."""
|
|
2
|
+
|
|
3
|
+
from swarmauri_core.transports.i_http_client import IHttpClient
|
|
4
|
+
from swarmauri_core.transports.i_http_retry_policy import IHttpRetryPolicy
|
|
5
|
+
from swarmauri_provider_xai import XAIProvider
|
|
6
|
+
from swarmauri_transport_httpx import HttpxClient
|
|
7
|
+
from swarmauri_transport_retry import RetryingHttpClient
|
|
8
|
+
|
|
9
|
+
from .XAIChatRetryPolicy import XAIChatRetryPolicy
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def build_xai_client(
|
|
13
|
+
*,
|
|
14
|
+
provider: XAIProvider,
|
|
15
|
+
http_client: IHttpClient | None,
|
|
16
|
+
retry_policy: IHttpRetryPolicy | None,
|
|
17
|
+
) -> IHttpClient:
|
|
18
|
+
concrete_client = http_client or HttpxClient(
|
|
19
|
+
base_url=provider.base_url,
|
|
20
|
+
timeout=provider.timeout,
|
|
21
|
+
)
|
|
22
|
+
return RetryingHttpClient(
|
|
23
|
+
client=concrete_client,
|
|
24
|
+
policy=retry_policy
|
|
25
|
+
or XAIChatRetryPolicy(max_attempts=max(provider.max_retries, 1)),
|
|
26
|
+
own_client=http_client is None,
|
|
27
|
+
)
|