nxuskit-py 1.0.3__py3-none-any.whl
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.
- nxuskit/__init__.py +287 -0
- nxuskit/__init__.pyi +248 -0
- nxuskit/_bn_ffi.py +64 -0
- nxuskit/_clips_ffi.py +61 -0
- nxuskit/_ffi.py +431 -0
- nxuskit/_ffi_errors.py +79 -0
- nxuskit/_ffi_provider.py +263 -0
- nxuskit/_ffi_types.py +124 -0
- nxuskit/_solver_ffi.py +61 -0
- nxuskit/_version.py +5 -0
- nxuskit/_zen_ffi.py +61 -0
- nxuskit/auth.py +323 -0
- nxuskit/auth_oauth.py +125 -0
- nxuskit/bn.py +485 -0
- nxuskit/clips.py +547 -0
- nxuskit/errors.py +85 -0
- nxuskit/libs/README.md +37 -0
- nxuskit/license.py +308 -0
- nxuskit/message.py +45 -0
- nxuskit/mock.py +84 -0
- nxuskit/plugin_trust.py +127 -0
- nxuskit/provider.py +97 -0
- nxuskit/providers/__init__.py +5 -0
- nxuskit/providers/base.py +209 -0
- nxuskit/providers/claude.py +378 -0
- nxuskit/providers/factory.py +329 -0
- nxuskit/providers/fireworks.py +41 -0
- nxuskit/providers/groq.py +41 -0
- nxuskit/providers/lmstudio.py +48 -0
- nxuskit/providers/mistral.py +41 -0
- nxuskit/providers/ollama.py +288 -0
- nxuskit/providers/openai.py +41 -0
- nxuskit/providers/openai_compatible.py +310 -0
- nxuskit/providers/openrouter.py +44 -0
- nxuskit/providers/perplexity.py +41 -0
- nxuskit/providers/together.py +41 -0
- nxuskit/providers/xai.py +41 -0
- nxuskit/py.typed +0 -0
- nxuskit/retry.py +308 -0
- nxuskit/security.py +144 -0
- nxuskit/solver.py +407 -0
- nxuskit/solver_types.py +396 -0
- nxuskit/streaming.py +218 -0
- nxuskit/tools.py +124 -0
- nxuskit/types.py +548 -0
- nxuskit/vision.py +259 -0
- nxuskit/zen.py +91 -0
- nxuskit_py-1.0.3.dist-info/METADATA +302 -0
- nxuskit_py-1.0.3.dist-info/RECORD +52 -0
- nxuskit_py-1.0.3.dist-info/WHEEL +4 -0
- nxuskit_py-1.0.3.dist-info/licenses/LICENSE +14 -0
- nxuskit_py-1.0.3.dist-info/licenses/NOTICE +10 -0
nxuskit/__init__.py
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""nxuskit - Pure Python library mirroring nxusKit Rust API."""
|
|
2
|
+
|
|
3
|
+
from nxuskit._ffi_errors import (
|
|
4
|
+
EditionInsufficientError,
|
|
5
|
+
FeatureUnavailableError,
|
|
6
|
+
LicenseExpiredError,
|
|
7
|
+
LicenseRequiredError,
|
|
8
|
+
NxuskitError,
|
|
9
|
+
)
|
|
10
|
+
from nxuskit._version import __author__, __license__, __version__
|
|
11
|
+
from nxuskit.errors import (
|
|
12
|
+
AuthenticationError,
|
|
13
|
+
LLMError,
|
|
14
|
+
NetworkError,
|
|
15
|
+
ProviderError,
|
|
16
|
+
RateLimitError,
|
|
17
|
+
TimeoutError,
|
|
18
|
+
)
|
|
19
|
+
from nxuskit.message import Message
|
|
20
|
+
from nxuskit.provider import LLMProvider
|
|
21
|
+
from nxuskit.providers import Provider
|
|
22
|
+
from nxuskit.retry import (
|
|
23
|
+
AdaptiveRateLimiter,
|
|
24
|
+
RetryConfig,
|
|
25
|
+
RetryIterator,
|
|
26
|
+
retry_on_rate_limit,
|
|
27
|
+
retry_with_backoff,
|
|
28
|
+
should_retry,
|
|
29
|
+
)
|
|
30
|
+
from nxuskit.security import (
|
|
31
|
+
SecurityIssue,
|
|
32
|
+
SecuritySeverity,
|
|
33
|
+
SecurityValidationResult,
|
|
34
|
+
SecurityValidator,
|
|
35
|
+
)
|
|
36
|
+
from nxuskit.solver_types import (
|
|
37
|
+
ConstraintDef,
|
|
38
|
+
ConstraintType,
|
|
39
|
+
DomainDef,
|
|
40
|
+
MultiObjectiveMode,
|
|
41
|
+
ObjectiveDef,
|
|
42
|
+
ObjectiveDirection,
|
|
43
|
+
SessionStatus,
|
|
44
|
+
SolverCapabilities,
|
|
45
|
+
SolverConfig,
|
|
46
|
+
SolveResult,
|
|
47
|
+
SolverExplanation,
|
|
48
|
+
SolverStats,
|
|
49
|
+
SolverValue,
|
|
50
|
+
SolveStatus,
|
|
51
|
+
VariableDef,
|
|
52
|
+
VariableType,
|
|
53
|
+
)
|
|
54
|
+
from nxuskit.streaming import (
|
|
55
|
+
StreamBuffer,
|
|
56
|
+
collect_stream,
|
|
57
|
+
stream_to_file,
|
|
58
|
+
stream_with_callback,
|
|
59
|
+
)
|
|
60
|
+
from nxuskit.tools import (
|
|
61
|
+
FunctionCall,
|
|
62
|
+
FunctionDefinition,
|
|
63
|
+
ToolCall,
|
|
64
|
+
ToolDefinition,
|
|
65
|
+
ToolResultMessage,
|
|
66
|
+
tool_choice_auto,
|
|
67
|
+
tool_choice_named,
|
|
68
|
+
tool_choice_none,
|
|
69
|
+
tool_choice_required,
|
|
70
|
+
)
|
|
71
|
+
from nxuskit.types import (
|
|
72
|
+
PUBLIC_CAPABILITY_FIELDS,
|
|
73
|
+
CapabilityStatus,
|
|
74
|
+
ChatRequest,
|
|
75
|
+
ChatResponse,
|
|
76
|
+
ImageSource,
|
|
77
|
+
ImageSourceType,
|
|
78
|
+
LogprobsData,
|
|
79
|
+
ManifestPublicationPosture,
|
|
80
|
+
ModelInfo,
|
|
81
|
+
PublicCapabilityManifest,
|
|
82
|
+
PublicProviderCapability,
|
|
83
|
+
ResponseFormat,
|
|
84
|
+
Role,
|
|
85
|
+
StreamChunk,
|
|
86
|
+
TokenLogprob,
|
|
87
|
+
TokenUsage,
|
|
88
|
+
TopLogprob,
|
|
89
|
+
)
|
|
90
|
+
from nxuskit.vision import (
|
|
91
|
+
ImageLoader,
|
|
92
|
+
add_images_to_message,
|
|
93
|
+
detect_image_type,
|
|
94
|
+
image_to_data_url,
|
|
95
|
+
is_base64,
|
|
96
|
+
is_valid_url,
|
|
97
|
+
load_image_base64,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# FFI-dependent modules are imported lazily to allow pure-Python usage
|
|
101
|
+
# (unit tests, type inspection) without the native library present.
|
|
102
|
+
# These modules load libnxuskit at import time via _ffi.py.
|
|
103
|
+
_FFI_NAMES = {
|
|
104
|
+
# auth_oauth
|
|
105
|
+
"OAuthResult",
|
|
106
|
+
"OAuthStatus",
|
|
107
|
+
"oauth_start",
|
|
108
|
+
"oauth_status",
|
|
109
|
+
"oauth_revoke",
|
|
110
|
+
# clips
|
|
111
|
+
"ClipsSession",
|
|
112
|
+
"ClipsError",
|
|
113
|
+
# license
|
|
114
|
+
"ActivationResult",
|
|
115
|
+
"LicenseResolution",
|
|
116
|
+
"TokenInfo",
|
|
117
|
+
"TrialResult",
|
|
118
|
+
"license_activate",
|
|
119
|
+
"license_deactivate",
|
|
120
|
+
"license_machine_id",
|
|
121
|
+
"license_resolve",
|
|
122
|
+
"license_trial_activate",
|
|
123
|
+
"license_trial_issue",
|
|
124
|
+
"license_validate",
|
|
125
|
+
# solver (stream chunk requires _solver_ffi)
|
|
126
|
+
"SolverStreamChunk",
|
|
127
|
+
# zen
|
|
128
|
+
"zen_evaluate",
|
|
129
|
+
"zen_evaluate_async",
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
_FFI_MODULE_MAP = {
|
|
133
|
+
"OAuthResult": "nxuskit.auth_oauth",
|
|
134
|
+
"OAuthStatus": "nxuskit.auth_oauth",
|
|
135
|
+
"oauth_start": "nxuskit.auth_oauth",
|
|
136
|
+
"oauth_status": "nxuskit.auth_oauth",
|
|
137
|
+
"oauth_revoke": "nxuskit.auth_oauth",
|
|
138
|
+
"ClipsSession": "nxuskit.clips",
|
|
139
|
+
"ClipsError": "nxuskit.clips",
|
|
140
|
+
"ActivationResult": "nxuskit.license",
|
|
141
|
+
"LicenseResolution": "nxuskit.license",
|
|
142
|
+
"TokenInfo": "nxuskit.license",
|
|
143
|
+
"TrialResult": "nxuskit.license",
|
|
144
|
+
"license_activate": "nxuskit.license",
|
|
145
|
+
"license_deactivate": "nxuskit.license",
|
|
146
|
+
"license_machine_id": "nxuskit.license",
|
|
147
|
+
"license_resolve": "nxuskit.license",
|
|
148
|
+
"license_trial_activate": "nxuskit.license",
|
|
149
|
+
"license_trial_issue": "nxuskit.license",
|
|
150
|
+
"license_validate": "nxuskit.license",
|
|
151
|
+
"SolverStreamChunk": "nxuskit.solver",
|
|
152
|
+
"zen_evaluate": "nxuskit.zen",
|
|
153
|
+
"zen_evaluate_async": "nxuskit.zen",
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def __getattr__(name: str):
|
|
158
|
+
if name in _FFI_NAMES:
|
|
159
|
+
import importlib
|
|
160
|
+
|
|
161
|
+
module = importlib.import_module(_FFI_MODULE_MAP[name])
|
|
162
|
+
value = getattr(module, name)
|
|
163
|
+
# Cache in module namespace for subsequent access
|
|
164
|
+
globals()[name] = value
|
|
165
|
+
return value
|
|
166
|
+
raise AttributeError(f"module 'nxuskit' has no attribute {name!r}")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
__all__ = [
|
|
170
|
+
"__version__",
|
|
171
|
+
"__author__",
|
|
172
|
+
"__license__",
|
|
173
|
+
# Types
|
|
174
|
+
"Role",
|
|
175
|
+
"ImageSourceType",
|
|
176
|
+
"ImageSource",
|
|
177
|
+
"TokenUsage",
|
|
178
|
+
"ChatRequest",
|
|
179
|
+
"ChatResponse",
|
|
180
|
+
"StreamChunk",
|
|
181
|
+
"ModelInfo",
|
|
182
|
+
"ResponseFormat",
|
|
183
|
+
"CapabilityStatus",
|
|
184
|
+
"ManifestPublicationPosture",
|
|
185
|
+
"PUBLIC_CAPABILITY_FIELDS",
|
|
186
|
+
"PublicProviderCapability",
|
|
187
|
+
"PublicCapabilityManifest",
|
|
188
|
+
"LogprobsData",
|
|
189
|
+
"TokenLogprob",
|
|
190
|
+
"TopLogprob",
|
|
191
|
+
# Message
|
|
192
|
+
"Message",
|
|
193
|
+
# Errors
|
|
194
|
+
"LLMError",
|
|
195
|
+
"AuthenticationError",
|
|
196
|
+
"RateLimitError",
|
|
197
|
+
"NetworkError",
|
|
198
|
+
"ProviderError",
|
|
199
|
+
"TimeoutError",
|
|
200
|
+
# FFI / entitlement errors
|
|
201
|
+
"NxuskitError",
|
|
202
|
+
"FeatureUnavailableError",
|
|
203
|
+
"LicenseRequiredError",
|
|
204
|
+
"LicenseExpiredError",
|
|
205
|
+
"EditionInsufficientError",
|
|
206
|
+
# Provider protocol
|
|
207
|
+
"LLMProvider",
|
|
208
|
+
# Provider factory
|
|
209
|
+
"Provider",
|
|
210
|
+
# Streaming utilities
|
|
211
|
+
"collect_stream",
|
|
212
|
+
"stream_with_callback",
|
|
213
|
+
"stream_to_file",
|
|
214
|
+
"StreamBuffer",
|
|
215
|
+
# Vision utilities
|
|
216
|
+
"load_image_base64",
|
|
217
|
+
"detect_image_type",
|
|
218
|
+
"is_valid_url",
|
|
219
|
+
"is_base64",
|
|
220
|
+
"add_images_to_message",
|
|
221
|
+
"image_to_data_url",
|
|
222
|
+
"ImageLoader",
|
|
223
|
+
# Retry utilities
|
|
224
|
+
"RetryConfig",
|
|
225
|
+
"should_retry",
|
|
226
|
+
"retry_with_backoff",
|
|
227
|
+
"retry_on_rate_limit",
|
|
228
|
+
"RetryIterator",
|
|
229
|
+
"AdaptiveRateLimiter",
|
|
230
|
+
# Solver types
|
|
231
|
+
"SolverStreamChunk",
|
|
232
|
+
"VariableType",
|
|
233
|
+
"VariableDef",
|
|
234
|
+
"DomainDef",
|
|
235
|
+
"ConstraintType",
|
|
236
|
+
"ConstraintDef",
|
|
237
|
+
"ObjectiveDirection",
|
|
238
|
+
"ObjectiveDef",
|
|
239
|
+
"MultiObjectiveMode",
|
|
240
|
+
"SolverConfig",
|
|
241
|
+
"SolveStatus",
|
|
242
|
+
"SolverValue",
|
|
243
|
+
"SolverStats",
|
|
244
|
+
"SolverExplanation",
|
|
245
|
+
"SolveResult",
|
|
246
|
+
"SolverCapabilities",
|
|
247
|
+
"SessionStatus",
|
|
248
|
+
# Tool calling
|
|
249
|
+
"ToolDefinition",
|
|
250
|
+
"FunctionDefinition",
|
|
251
|
+
"ToolCall",
|
|
252
|
+
"FunctionCall",
|
|
253
|
+
"ToolResultMessage",
|
|
254
|
+
"tool_choice_auto",
|
|
255
|
+
"tool_choice_none",
|
|
256
|
+
"tool_choice_required",
|
|
257
|
+
"tool_choice_named",
|
|
258
|
+
# CLIPS Session (FFI-dependent, lazy-loaded)
|
|
259
|
+
"ClipsSession",
|
|
260
|
+
"ClipsError",
|
|
261
|
+
# License management (FFI-dependent, lazy-loaded)
|
|
262
|
+
"ActivationResult",
|
|
263
|
+
"LicenseResolution",
|
|
264
|
+
"TokenInfo",
|
|
265
|
+
"TrialResult",
|
|
266
|
+
"license_activate",
|
|
267
|
+
"license_deactivate",
|
|
268
|
+
"license_machine_id",
|
|
269
|
+
"license_resolve",
|
|
270
|
+
"license_trial_activate",
|
|
271
|
+
"license_trial_issue",
|
|
272
|
+
"license_validate",
|
|
273
|
+
# OAuth authentication (FFI-dependent, lazy-loaded)
|
|
274
|
+
"OAuthResult",
|
|
275
|
+
"OAuthStatus",
|
|
276
|
+
"oauth_start",
|
|
277
|
+
"oauth_status",
|
|
278
|
+
"oauth_revoke",
|
|
279
|
+
# ZEN evaluation (FFI-dependent, lazy-loaded)
|
|
280
|
+
"zen_evaluate",
|
|
281
|
+
"zen_evaluate_async",
|
|
282
|
+
# Security validation
|
|
283
|
+
"SecurityValidator",
|
|
284
|
+
"SecurityValidationResult",
|
|
285
|
+
"SecurityIssue",
|
|
286
|
+
"SecuritySeverity",
|
|
287
|
+
]
|
nxuskit/__init__.pyi
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"""PEP 561 type stubs for the nxuskit package."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any, Iterator, Optional, Protocol, Union
|
|
6
|
+
|
|
7
|
+
# ── Core Types ──────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
class CapabilityStatus(str, Enum):
|
|
10
|
+
SUPPORTED: str
|
|
11
|
+
UNSUPPORTED: str
|
|
12
|
+
RECOGNIZED: str
|
|
13
|
+
PROVIDER_SPECIFIC: str
|
|
14
|
+
FUTURE: str
|
|
15
|
+
UNKNOWN: str
|
|
16
|
+
|
|
17
|
+
class ManifestPublicationPosture(str, Enum):
|
|
18
|
+
SPLIT: str
|
|
19
|
+
|
|
20
|
+
PUBLIC_CAPABILITY_FIELDS: tuple[str, ...]
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class PublicProviderCapability:
|
|
24
|
+
name: str
|
|
25
|
+
display_name: str
|
|
26
|
+
last_reviewed_on: str
|
|
27
|
+
provider_status: str
|
|
28
|
+
capabilities: dict[str, CapabilityStatus]
|
|
29
|
+
def to_dict(self) -> dict[str, Any]: ...
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class PublicCapabilityManifest:
|
|
33
|
+
schema_version: str
|
|
34
|
+
posture: ManifestPublicationPosture
|
|
35
|
+
providers: list[PublicProviderCapability]
|
|
36
|
+
def to_dict(self) -> dict[str, Any]: ...
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class TokenUsage:
|
|
40
|
+
input_tokens: int
|
|
41
|
+
output_tokens: int
|
|
42
|
+
total_tokens: int
|
|
43
|
+
@property
|
|
44
|
+
def prompt_tokens(self) -> int: ...
|
|
45
|
+
@property
|
|
46
|
+
def completion_tokens(self) -> int: ...
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class ChatResponse:
|
|
50
|
+
content: Optional[str]
|
|
51
|
+
usage: TokenUsage
|
|
52
|
+
model: str
|
|
53
|
+
finish_reason: Optional[str]
|
|
54
|
+
tool_calls: Optional[list]
|
|
55
|
+
provider: Optional[str]
|
|
56
|
+
warnings: list[str]
|
|
57
|
+
@property
|
|
58
|
+
def stop_reason(self) -> Optional[str]: ...
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class StreamChunk:
|
|
62
|
+
delta: str
|
|
63
|
+
model: Optional[str]
|
|
64
|
+
finish_reason: Optional[str]
|
|
65
|
+
thinking: Optional[str]
|
|
66
|
+
usage: Optional[TokenUsage]
|
|
67
|
+
tool_calls: Optional[list]
|
|
68
|
+
def is_final(self) -> bool: ...
|
|
69
|
+
def has_thinking(self) -> bool: ...
|
|
70
|
+
def has_tool_calls(self) -> bool: ...
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class ModelInfo:
|
|
74
|
+
id: str
|
|
75
|
+
name: str
|
|
76
|
+
description: Optional[str]
|
|
77
|
+
size_bytes: Optional[int]
|
|
78
|
+
context_window: Optional[int]
|
|
79
|
+
provider: str
|
|
80
|
+
metadata: dict[str, str]
|
|
81
|
+
def supports_vision(self) -> bool: ...
|
|
82
|
+
def modalities(self) -> list[str]: ...
|
|
83
|
+
def max_images(self) -> Optional[int]: ...
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_dict(cls, data: dict) -> "ModelInfo": ...
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class ImageSource:
|
|
89
|
+
source_type: Any # ImageSourceType enum
|
|
90
|
+
data: str
|
|
91
|
+
media_type: Optional[str]
|
|
92
|
+
|
|
93
|
+
# ── Message ─────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
@dataclass
|
|
96
|
+
class Message:
|
|
97
|
+
role: Any # Role enum
|
|
98
|
+
content: str
|
|
99
|
+
images: list[ImageSource]
|
|
100
|
+
@staticmethod
|
|
101
|
+
def user(content: str) -> "Message": ...
|
|
102
|
+
@staticmethod
|
|
103
|
+
def assistant(content: str) -> "Message": ...
|
|
104
|
+
@staticmethod
|
|
105
|
+
def system(content: str) -> "Message": ...
|
|
106
|
+
def with_image_url(self, url: str) -> "Message": ...
|
|
107
|
+
def with_image_base64(self, data: str) -> "Message": ...
|
|
108
|
+
def with_image_file(self, path: str) -> "Message": ...
|
|
109
|
+
|
|
110
|
+
# ── Tool Calling ────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
@dataclass
|
|
113
|
+
class FunctionDefinition:
|
|
114
|
+
name: str
|
|
115
|
+
description: str
|
|
116
|
+
parameters: dict
|
|
117
|
+
|
|
118
|
+
@dataclass
|
|
119
|
+
class ToolDefinition:
|
|
120
|
+
type: str
|
|
121
|
+
function: FunctionDefinition
|
|
122
|
+
@staticmethod
|
|
123
|
+
def create(name: str, description: str, parameters: dict) -> "ToolDefinition": ...
|
|
124
|
+
def to_dict(self) -> dict: ...
|
|
125
|
+
|
|
126
|
+
@dataclass
|
|
127
|
+
class FunctionCall:
|
|
128
|
+
name: str
|
|
129
|
+
arguments: str
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class ToolCall:
|
|
133
|
+
id: str
|
|
134
|
+
type: str
|
|
135
|
+
function: FunctionCall
|
|
136
|
+
@classmethod
|
|
137
|
+
def from_dict(cls, data: dict) -> "ToolCall": ...
|
|
138
|
+
|
|
139
|
+
def tool_choice_auto() -> str: ...
|
|
140
|
+
def tool_choice_none() -> str: ...
|
|
141
|
+
def tool_choice_required() -> str: ...
|
|
142
|
+
def tool_choice_named(name: str) -> dict: ...
|
|
143
|
+
|
|
144
|
+
# ── Provider Protocol ───────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
class LLMProvider(Protocol):
|
|
147
|
+
@property
|
|
148
|
+
def model(self) -> str: ...
|
|
149
|
+
@property
|
|
150
|
+
def provider_name(self) -> str: ...
|
|
151
|
+
def chat(
|
|
152
|
+
self,
|
|
153
|
+
messages: list[Message],
|
|
154
|
+
*,
|
|
155
|
+
model: Optional[str] = ...,
|
|
156
|
+
temperature: Optional[float] = ...,
|
|
157
|
+
max_tokens: Optional[int] = ...,
|
|
158
|
+
top_p: Optional[float] = ...,
|
|
159
|
+
stop: Optional[Union[str, list[str]]] = ...,
|
|
160
|
+
response_format: Optional[Any] = ...,
|
|
161
|
+
tools: Optional[list[ToolDefinition]] = ...,
|
|
162
|
+
tool_choice: Optional[Any] = ...,
|
|
163
|
+
) -> ChatResponse: ...
|
|
164
|
+
def chat_stream(
|
|
165
|
+
self,
|
|
166
|
+
messages: list[Message],
|
|
167
|
+
*,
|
|
168
|
+
model: Optional[str] = ...,
|
|
169
|
+
temperature: Optional[float] = ...,
|
|
170
|
+
max_tokens: Optional[int] = ...,
|
|
171
|
+
top_p: Optional[float] = ...,
|
|
172
|
+
stop: Optional[Union[str, list[str]]] = ...,
|
|
173
|
+
response_format: Optional[Any] = ...,
|
|
174
|
+
tools: Optional[list[ToolDefinition]] = ...,
|
|
175
|
+
tool_choice: Optional[Any] = ...,
|
|
176
|
+
) -> Iterator[StreamChunk]: ...
|
|
177
|
+
def list_models(self) -> list[ModelInfo]: ...
|
|
178
|
+
|
|
179
|
+
# ── Provider Factory ────────────────────────────────────────────
|
|
180
|
+
|
|
181
|
+
class Provider:
|
|
182
|
+
@staticmethod
|
|
183
|
+
def claude(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
184
|
+
@staticmethod
|
|
185
|
+
def openai(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
186
|
+
@staticmethod
|
|
187
|
+
def ollama(*, model: str = ..., **kwargs: Any) -> Any: ...
|
|
188
|
+
@staticmethod
|
|
189
|
+
def groq(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
190
|
+
@staticmethod
|
|
191
|
+
def xai(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
192
|
+
@staticmethod
|
|
193
|
+
def mistral(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
194
|
+
@staticmethod
|
|
195
|
+
def fireworks(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
196
|
+
@staticmethod
|
|
197
|
+
def together(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
198
|
+
@staticmethod
|
|
199
|
+
def openrouter(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
200
|
+
@staticmethod
|
|
201
|
+
def perplexity(*, model: str = ..., api_key: Optional[str] = ..., **kwargs: Any) -> Any: ...
|
|
202
|
+
@staticmethod
|
|
203
|
+
def lmstudio(*, model: str = ..., **kwargs: Any) -> Any: ...
|
|
204
|
+
|
|
205
|
+
# ── Errors ──────────────────────────────────────────────────────
|
|
206
|
+
|
|
207
|
+
class LLMError(Exception):
|
|
208
|
+
status_code: Optional[int]
|
|
209
|
+
provider: Optional[str]
|
|
210
|
+
model: Optional[str]
|
|
211
|
+
@property
|
|
212
|
+
def is_retryable(self) -> bool: ...
|
|
213
|
+
|
|
214
|
+
class AuthenticationError(LLMError): ...
|
|
215
|
+
|
|
216
|
+
class RateLimitError(LLMError):
|
|
217
|
+
retry_after: Optional[float]
|
|
218
|
+
|
|
219
|
+
class NetworkError(LLMError): ...
|
|
220
|
+
class TimeoutError(LLMError): ...
|
|
221
|
+
class ProviderError(LLMError): ...
|
|
222
|
+
|
|
223
|
+
# FFI errors
|
|
224
|
+
class NxuskitError(Exception):
|
|
225
|
+
error_type: str
|
|
226
|
+
message: str
|
|
227
|
+
provider: Optional[str]
|
|
228
|
+
feature: Optional[str]
|
|
229
|
+
|
|
230
|
+
class ConfigError(NxuskitError): ...
|
|
231
|
+
class FeatureUnavailableError(NxuskitError): ...
|
|
232
|
+
class LicenseRequiredError(NxuskitError): ...
|
|
233
|
+
class LicenseExpiredError(NxuskitError): ...
|
|
234
|
+
|
|
235
|
+
class EditionInsufficientError(NxuskitError):
|
|
236
|
+
required_edition: Optional[str]
|
|
237
|
+
|
|
238
|
+
# ── FFI Provider ────────────────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
class FFIProvider:
|
|
241
|
+
def chat(self, request: dict[str, Any]) -> ChatResponse: ...
|
|
242
|
+
def stream(self, request: dict[str, Any]) -> Iterator[StreamChunk]: ...
|
|
243
|
+
def list_models(self) -> list[ModelInfo]: ...
|
|
244
|
+
def close(self) -> None: ...
|
|
245
|
+
def __enter__(self) -> "FFIProvider": ...
|
|
246
|
+
def __exit__(self, *args: Any) -> None: ...
|
|
247
|
+
|
|
248
|
+
def create_ffi_provider(config: dict[str, Any]) -> FFIProvider: ...
|
nxuskit/_bn_ffi.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Low-level cffi bindings for the Bayesian Network C ABI.
|
|
2
|
+
|
|
3
|
+
Uses the shared FFI instance and library handle from _ffi.py.
|
|
4
|
+
Higher-level Python wrappers are in bn.py.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BnLibraryNotFoundError(RuntimeError):
|
|
11
|
+
"""Raised when the nxuskit native library cannot be found."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Lazy reference — populated on first _get_lib() call.
|
|
15
|
+
_bn_lib = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _get_lib():
|
|
19
|
+
"""Get the shared library handle for BN functions."""
|
|
20
|
+
global _bn_lib
|
|
21
|
+
if _bn_lib is not None:
|
|
22
|
+
return _bn_lib
|
|
23
|
+
try:
|
|
24
|
+
from nxuskit._ffi import lib
|
|
25
|
+
|
|
26
|
+
_bn_lib = lib
|
|
27
|
+
return _bn_lib
|
|
28
|
+
except Exception as e:
|
|
29
|
+
raise BnLibraryNotFoundError(
|
|
30
|
+
f"Failed to load nxuskit native library: {e}. "
|
|
31
|
+
"Set NXUSKIT_LIB_DIR, NXUSKIT_SDK_DIR, or install at ~/.nxuskit/sdk/current/."
|
|
32
|
+
) from e
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def last_error() -> str:
|
|
36
|
+
"""Read the thread-local error message from the C ABI."""
|
|
37
|
+
from nxuskit._ffi import ffi
|
|
38
|
+
|
|
39
|
+
lib = _get_lib()
|
|
40
|
+
ptr = lib.nxuskit_last_error()
|
|
41
|
+
if ptr == ffi.NULL:
|
|
42
|
+
return ""
|
|
43
|
+
return ffi.string(ptr).decode("utf-8", errors="replace")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def read_and_free_string(ptr) -> str:
|
|
47
|
+
"""Convert a C string to Python, free the C memory."""
|
|
48
|
+
from nxuskit._ffi import ffi
|
|
49
|
+
|
|
50
|
+
lib = _get_lib()
|
|
51
|
+
if ptr == ffi.NULL:
|
|
52
|
+
err = last_error()
|
|
53
|
+
raise RuntimeError(f"nxuskit bn: NULL string returned: {err}")
|
|
54
|
+
s = ffi.string(ptr).decode("utf-8")
|
|
55
|
+
lib.nxuskit_free_string(ptr)
|
|
56
|
+
return s
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Backward compat: code that imported bn_ffi directly can still use it
|
|
60
|
+
# for callback definitions. Point to the shared ffi instance.
|
|
61
|
+
try:
|
|
62
|
+
from nxuskit._ffi import ffi as bn_ffi
|
|
63
|
+
except Exception:
|
|
64
|
+
bn_ffi = None # type: ignore[assignment]
|
nxuskit/_clips_ffi.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Low-level cffi bindings for the CLIPS Session C ABI.
|
|
2
|
+
|
|
3
|
+
Uses the shared FFI instance and library handle from _ffi.py.
|
|
4
|
+
Higher-level Python wrappers are in clips.py.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ClipsLibraryNotFoundError(RuntimeError):
|
|
11
|
+
"""Raised when the nxuskit native library cannot be found."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_clips_lib = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _get_lib():
|
|
18
|
+
"""Get the shared library handle for CLIPS functions."""
|
|
19
|
+
global _clips_lib
|
|
20
|
+
if _clips_lib is not None:
|
|
21
|
+
return _clips_lib
|
|
22
|
+
try:
|
|
23
|
+
from nxuskit._ffi import lib
|
|
24
|
+
|
|
25
|
+
_clips_lib = lib
|
|
26
|
+
return _clips_lib
|
|
27
|
+
except Exception as e:
|
|
28
|
+
raise ClipsLibraryNotFoundError(
|
|
29
|
+
f"Failed to load nxuskit native library: {e}. "
|
|
30
|
+
"Set NXUSKIT_LIB_DIR, NXUSKIT_SDK_DIR, or install at ~/.nxuskit/sdk/current/."
|
|
31
|
+
) from e
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def last_error() -> str:
|
|
35
|
+
"""Read the thread-local error message from the C ABI."""
|
|
36
|
+
from nxuskit._ffi import ffi
|
|
37
|
+
|
|
38
|
+
lib = _get_lib()
|
|
39
|
+
ptr = lib.nxuskit_last_error()
|
|
40
|
+
if ptr == ffi.NULL:
|
|
41
|
+
return ""
|
|
42
|
+
return ffi.string(ptr).decode("utf-8", errors="replace")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def read_and_free_string(ptr) -> str:
|
|
46
|
+
"""Convert a C string to Python, free the C memory."""
|
|
47
|
+
from nxuskit._ffi import ffi
|
|
48
|
+
|
|
49
|
+
lib = _get_lib()
|
|
50
|
+
if ptr == ffi.NULL:
|
|
51
|
+
err = last_error()
|
|
52
|
+
raise RuntimeError(f"nxuskit clips: NULL string returned: {err}")
|
|
53
|
+
s = ffi.string(ptr).decode("utf-8")
|
|
54
|
+
lib.nxuskit_free_string(ptr)
|
|
55
|
+
return s
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
from nxuskit._ffi import ffi as clips_ffi
|
|
60
|
+
except Exception:
|
|
61
|
+
clips_ffi = None # type: ignore[assignment]
|