acruxcore 0.4.1__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.
- acruxcore/__init__.py +81 -0
- acruxcore/cache.py +66 -0
- acruxcore/client.py +886 -0
- acruxcore/errors.py +48 -0
- acruxcore/http.py +76 -0
- acruxcore/py.typed +0 -0
- acruxcore/types.py +368 -0
- acruxcore-0.4.1.dist-info/METADATA +246 -0
- acruxcore-0.4.1.dist-info/RECORD +10 -0
- acruxcore-0.4.1.dist-info/WHEEL +4 -0
acruxcore/__init__.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Async Python SDK for Acrux Core.
|
|
2
|
+
|
|
3
|
+
Runtime prompt render, gateway chat (with streaming), client-side tool loops,
|
|
4
|
+
trace reporting, and feedback — full parity with the TypeScript SDK.
|
|
5
|
+
|
|
6
|
+
Example::
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
from acruxcore import AcruxCore
|
|
10
|
+
|
|
11
|
+
async def main():
|
|
12
|
+
async with AcruxCore(api_key=..., base_url="http://localhost:3000/api/v1") as hub:
|
|
13
|
+
result = await hub.render_prompt("greeting", "production", {"name": "Alice"})
|
|
14
|
+
print(result.messages)
|
|
15
|
+
|
|
16
|
+
asyncio.run(main())
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from .client import AcruxCore, AsyncChatStream
|
|
20
|
+
from .errors import (
|
|
21
|
+
API_ERROR,
|
|
22
|
+
MISSING_API_KEY,
|
|
23
|
+
MISSING_BASE_URL,
|
|
24
|
+
MISSING_VARIABLES,
|
|
25
|
+
NETWORK_ERROR,
|
|
26
|
+
AcruxCoreError,
|
|
27
|
+
)
|
|
28
|
+
from .types import (
|
|
29
|
+
ChatChunk,
|
|
30
|
+
ChatResult,
|
|
31
|
+
ChatUsage,
|
|
32
|
+
FeedbackResult,
|
|
33
|
+
GatewayCallMeta,
|
|
34
|
+
GetTraceResult,
|
|
35
|
+
IngestSpan,
|
|
36
|
+
ListTracesResult,
|
|
37
|
+
Message,
|
|
38
|
+
RenderResult,
|
|
39
|
+
RunToolLoopResult,
|
|
40
|
+
ToolCall,
|
|
41
|
+
ToolChoice,
|
|
42
|
+
ToolDefinition,
|
|
43
|
+
ToolRef,
|
|
44
|
+
TraceInput,
|
|
45
|
+
TraceResult,
|
|
46
|
+
TraceSpan,
|
|
47
|
+
TraceSummary,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
__version__ = "0.4.1"
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"AcruxCore",
|
|
54
|
+
"AsyncChatStream",
|
|
55
|
+
"AcruxCoreError",
|
|
56
|
+
"API_ERROR",
|
|
57
|
+
"MISSING_API_KEY",
|
|
58
|
+
"MISSING_BASE_URL",
|
|
59
|
+
"MISSING_VARIABLES",
|
|
60
|
+
"NETWORK_ERROR",
|
|
61
|
+
"ChatChunk",
|
|
62
|
+
"ChatResult",
|
|
63
|
+
"ChatUsage",
|
|
64
|
+
"FeedbackResult",
|
|
65
|
+
"GatewayCallMeta",
|
|
66
|
+
"GetTraceResult",
|
|
67
|
+
"IngestSpan",
|
|
68
|
+
"ListTracesResult",
|
|
69
|
+
"Message",
|
|
70
|
+
"RenderResult",
|
|
71
|
+
"RunToolLoopResult",
|
|
72
|
+
"ToolCall",
|
|
73
|
+
"ToolChoice",
|
|
74
|
+
"ToolDefinition",
|
|
75
|
+
"ToolRef",
|
|
76
|
+
"TraceInput",
|
|
77
|
+
"TraceResult",
|
|
78
|
+
"TraceSpan",
|
|
79
|
+
"TraceSummary",
|
|
80
|
+
"__version__",
|
|
81
|
+
]
|
acruxcore/cache.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Module-level LRU cache for rendered prompts (stale-while-revalidate).
|
|
2
|
+
|
|
3
|
+
Mirrors the TypeScript SDK's ``cache.ts``: a process-wide singleton so that a
|
|
4
|
+
stale entry can be served while a background refresh is in flight. ``max_size``
|
|
5
|
+
is honoured only on the first :func:`get_cache` call — reuse one client.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from collections import OrderedDict
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
from .types import RenderResult
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class CacheEntry:
|
|
19
|
+
"""One cache slot: the rendered value plus the epoch-ms it was fetched at."""
|
|
20
|
+
|
|
21
|
+
value: RenderResult
|
|
22
|
+
fetched_at: float # epoch milliseconds
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _LRUCache:
|
|
26
|
+
"""A tiny LRU cache keyed by string, bounded by ``max_size`` entries."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, max_size: int) -> None:
|
|
29
|
+
self._max = max_size
|
|
30
|
+
self._store: "OrderedDict[str, CacheEntry]" = OrderedDict()
|
|
31
|
+
|
|
32
|
+
def get(self, key: str) -> Optional[CacheEntry]:
|
|
33
|
+
entry = self._store.get(key)
|
|
34
|
+
if entry is not None:
|
|
35
|
+
self._store.move_to_end(key) # mark most-recently-used
|
|
36
|
+
return entry
|
|
37
|
+
|
|
38
|
+
def set(self, key: str, entry: CacheEntry) -> None:
|
|
39
|
+
self._store[key] = entry
|
|
40
|
+
self._store.move_to_end(key)
|
|
41
|
+
while len(self._store) > self._max:
|
|
42
|
+
self._store.popitem(last=False) # evict least-recently-used
|
|
43
|
+
|
|
44
|
+
def clear(self) -> None:
|
|
45
|
+
self._store.clear()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
_cache: Optional[_LRUCache] = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_cache(max_size: int) -> _LRUCache:
|
|
52
|
+
"""Return the process-wide LRU cache, creating it on the first call.
|
|
53
|
+
|
|
54
|
+
:param max_size: Maximum entries. Effective only on the first call.
|
|
55
|
+
:returns: The shared cache instance.
|
|
56
|
+
"""
|
|
57
|
+
global _cache
|
|
58
|
+
if _cache is None:
|
|
59
|
+
_cache = _LRUCache(max_size)
|
|
60
|
+
return _cache
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _reset_cache_for_testing() -> None:
|
|
64
|
+
"""Reset the singleton. FOR TESTING ONLY."""
|
|
65
|
+
global _cache
|
|
66
|
+
_cache = None
|