swisper-studio-sdk 0.5.0__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.
- swisper_studio_sdk-0.5.0/PKG-INFO +253 -0
- swisper_studio_sdk-0.5.0/README.md +234 -0
- swisper_studio_sdk-0.5.0/pyproject.toml +34 -0
- swisper_studio_sdk-0.5.0/setup.cfg +4 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/__init__.py +56 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/tracing/__init__.py +2 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/tracing/client.py +276 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/tracing/context.py +37 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/tracing/decorator.py +337 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/tracing/graph_wrapper.py +320 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/tracing/redis_publisher.py +310 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/tracing/tool_observer.py +350 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/wrappers/__init__.py +18 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/wrappers/llm_wrapper.py +355 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk/wrappers/tool_wrapper.py +74 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk.egg-info/PKG-INFO +253 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk.egg-info/SOURCES.txt +24 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk.egg-info/dependency_links.txt +1 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk.egg-info/requires.txt +8 -0
- swisper_studio_sdk-0.5.0/swisper_studio_sdk.egg-info/top_level.txt +1 -0
- swisper_studio_sdk-0.5.0/tests/test_fire_and_forget.py +140 -0
- swisper_studio_sdk-0.5.0/tests/test_llm_wrapper.py +140 -0
- swisper_studio_sdk-0.5.0/tests/test_llm_wrapper_integration.py +101 -0
- swisper_studio_sdk-0.5.0/tests/test_parent_observation.py +72 -0
- swisper_studio_sdk-0.5.0/tests/test_state_capture.py +117 -0
- swisper_studio_sdk-0.5.0/tests/test_type_detection.py +55 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: swisper-studio-sdk
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: SwisperStudio SDK - Tracing integration for Swisper (internal use)
|
|
5
|
+
Author: Fintama SwisperStudio Team
|
|
6
|
+
License: Proprietary - Fintama Internal Use Only
|
|
7
|
+
Project-URL: Homepage, https://github.com/Fintama/swisper_studio
|
|
8
|
+
Project-URL: Repository, https://github.com/Fintama/swisper_studio
|
|
9
|
+
Project-URL: Documentation, https://github.com/Fintama/swisper_studio/tree/main/sdk
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: httpx>=0.25.2
|
|
13
|
+
Requires-Dist: langgraph<2.0.0,>=1.0.0
|
|
14
|
+
Requires-Dist: langgraph-checkpoint<3.0.0,>=2.1.0
|
|
15
|
+
Requires-Dist: redis>=5.0.0
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest>=7.4.3; extra == "dev"
|
|
18
|
+
Requires-Dist: pytest-asyncio>=0.21.1; extra == "dev"
|
|
19
|
+
|
|
20
|
+
# SwisperStudio SDK
|
|
21
|
+
|
|
22
|
+
Simple, high-performance integration for tracing Swisper LangGraph applications.
|
|
23
|
+
|
|
24
|
+
**v0.4.0 - Redis Streams Architecture:**
|
|
25
|
+
- 🚀 **50x faster** - 500ms → 10ms overhead
|
|
26
|
+
- 🧠 **LLM reasoning** - See thinking process (`<think>...</think>`)
|
|
27
|
+
- 📡 **Connection status** - Heartbeat-based health monitoring
|
|
28
|
+
- ⚙️ **Per-node config** - Fine-grained control
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### From PyPI (Recommended)
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install swisper-studio-sdk==0.5.0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
That's it! No authentication needed.
|
|
39
|
+
|
|
40
|
+
### From Source (Development)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/Fintama/swisper_studio.git
|
|
44
|
+
cd swisper_studio/sdk
|
|
45
|
+
pip install -e .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Note:** Source installation requires Fintama GitHub organization access.
|
|
49
|
+
|
|
50
|
+
## Quick Start (30 seconds)
|
|
51
|
+
|
|
52
|
+
### 1. Initialize at Startup (Redis Streams)
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
# In your main.py or startup code
|
|
56
|
+
from swisper_studio_sdk import initialize_redis_publisher
|
|
57
|
+
|
|
58
|
+
# Async initialization (in lifespan or startup)
|
|
59
|
+
await initialize_redis_publisher(
|
|
60
|
+
redis_url="redis://redis:6379", # Your Redis instance
|
|
61
|
+
project_id="your-project-id", # From SwisperStudio
|
|
62
|
+
stream_name="observability:events", # Default stream name
|
|
63
|
+
verify_consumer=True, # Check SwisperStudio is running
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 2. ONE LINE CHANGE to Enable Tracing
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
# Before:
|
|
71
|
+
from langgraph.graph import StateGraph
|
|
72
|
+
graph = StateGraph(GlobalSupervisorState)
|
|
73
|
+
|
|
74
|
+
# After (change ONE line):
|
|
75
|
+
from swisper_studio_sdk import create_traced_graph
|
|
76
|
+
graph = create_traced_graph(GlobalSupervisorState, trace_name="supervisor")
|
|
77
|
+
|
|
78
|
+
# That's it! All nodes added to this graph are automatically traced!
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 3. Add Nodes as Normal
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
# Add nodes - they're automatically traced!
|
|
85
|
+
graph.add_node("intent_classification", intent_classification_node)
|
|
86
|
+
graph.add_node("memory", memory_node)
|
|
87
|
+
graph.add_node("planner", planner_node)
|
|
88
|
+
graph.add_node("ui_node", ui_node)
|
|
89
|
+
|
|
90
|
+
# Compile and run as usual
|
|
91
|
+
app = graph.compile()
|
|
92
|
+
result = await app.ainvoke(initial_state)
|
|
93
|
+
|
|
94
|
+
# All executions are now traced to SwisperStudio! 🎉
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Features
|
|
98
|
+
|
|
99
|
+
### **Core Features:**
|
|
100
|
+
- ✅ **One-line integration** - `create_traced_graph()` instead of `StateGraph()`
|
|
101
|
+
- ✅ **Auto-instrumentation** - All nodes automatically traced
|
|
102
|
+
- ✅ **State capture** - Captures input/output state at each node
|
|
103
|
+
- ✅ **Error tracking** - Captures exceptions and error messages
|
|
104
|
+
- ✅ **Nested observations** - Supports parent-child relationships
|
|
105
|
+
- ✅ **Zero boilerplate** - No decorators needed on individual nodes
|
|
106
|
+
|
|
107
|
+
### **v0.4.0 New Features:**
|
|
108
|
+
- ✅ **Redis Streams** - 50x faster than HTTP (500ms → 10ms)
|
|
109
|
+
- ✅ **LLM Reasoning** - Captures `<think>...</think>` tags from DeepSeek R1, o1, etc.
|
|
110
|
+
- ✅ **Streaming Support** - Captures full responses from streaming LLM calls
|
|
111
|
+
- ✅ **Connection Status** - Verifies SwisperStudio consumer is running
|
|
112
|
+
- ✅ **Per-Node Config** - Enable/disable reasoning per node
|
|
113
|
+
- ✅ **Memory Safety** - Auto-cleanup prevents memory leaks
|
|
114
|
+
|
|
115
|
+
## Advanced Usage
|
|
116
|
+
|
|
117
|
+
### LLM Reasoning Capture
|
|
118
|
+
|
|
119
|
+
Control reasoning capture per node:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from swisper_studio_sdk import traced
|
|
123
|
+
|
|
124
|
+
# Enable reasoning with custom length limit
|
|
125
|
+
@traced("classify_intent", capture_reasoning=True, reasoning_max_length=20000)
|
|
126
|
+
async def classify_intent_node(state):
|
|
127
|
+
# Captures <think>...</think> tags (up to 20KB)
|
|
128
|
+
return state
|
|
129
|
+
|
|
130
|
+
# Disable reasoning for specific nodes
|
|
131
|
+
@traced("memory_node", capture_reasoning=False)
|
|
132
|
+
async def memory_node(state):
|
|
133
|
+
# No reasoning captured (faster, less data)
|
|
134
|
+
return state
|
|
135
|
+
|
|
136
|
+
# Use defaults (reasoning enabled, 50KB limit)
|
|
137
|
+
@traced("global_planner")
|
|
138
|
+
async def global_planner_node(state):
|
|
139
|
+
return state
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**What gets captured:**
|
|
143
|
+
- ✅ LLM prompts (system + user messages)
|
|
144
|
+
- ✅ Reasoning process (`<think>...</think>` tags)
|
|
145
|
+
- ✅ Final responses (structured output or streaming)
|
|
146
|
+
- ✅ Token usage (prompt + completion)
|
|
147
|
+
|
|
148
|
+
**Supported models:**
|
|
149
|
+
- DeepSeek R1 (with reasoning)
|
|
150
|
+
- OpenAI o1/o3 (with reasoning)
|
|
151
|
+
- GPT-4, Claude, Llama (no reasoning, just prompts + responses)
|
|
152
|
+
|
|
153
|
+
### Manual Tracing (Optional)
|
|
154
|
+
|
|
155
|
+
For fine-grained control, use `@traced` decorator:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from swisper_studio_sdk import traced
|
|
159
|
+
|
|
160
|
+
# Full control over observation
|
|
161
|
+
@traced(
|
|
162
|
+
name="intent_classification",
|
|
163
|
+
observation_type="GENERATION",
|
|
164
|
+
capture_reasoning=True,
|
|
165
|
+
reasoning_max_length=10000
|
|
166
|
+
)
|
|
167
|
+
async def intent_classification_node(state):
|
|
168
|
+
return state
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Observation Types
|
|
172
|
+
|
|
173
|
+
- `AUTO` - Auto-detect based on LLM data (default, recommended)
|
|
174
|
+
- `SPAN` - Generic execution span
|
|
175
|
+
- `GENERATION` - LLM generation
|
|
176
|
+
- `EVENT` - Point-in-time event
|
|
177
|
+
- `TOOL` - Tool call
|
|
178
|
+
- `AGENT` - Agent execution
|
|
179
|
+
|
|
180
|
+
## Architecture
|
|
181
|
+
|
|
182
|
+
### Redis Streams (v0.4.0)
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
Your App (Swisper) Redis Stream SwisperStudio
|
|
186
|
+
│ │ │
|
|
187
|
+
@traced decorator │ │
|
|
188
|
+
│ │ │
|
|
189
|
+
XADD event (1-2ms) ──────────→ │ │
|
|
190
|
+
│ │ │
|
|
191
|
+
Return immediately │ │
|
|
192
|
+
(zero latency!) │ │
|
|
193
|
+
│ Consumer reads batch │
|
|
194
|
+
│ ←─────────────────────────┤
|
|
195
|
+
│ │
|
|
196
|
+
│ Store in PostgreSQL │
|
|
197
|
+
│ ──────────────────────────→
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Benefits:**
|
|
201
|
+
- **50x faster** than HTTP (500ms → 10ms overhead)
|
|
202
|
+
- **No race conditions** (ordered stream delivery)
|
|
203
|
+
- **Reliable** (persistent queue, automatic retry)
|
|
204
|
+
- **Scalable** (100k+ events/sec)
|
|
205
|
+
|
|
206
|
+
### How It Works
|
|
207
|
+
|
|
208
|
+
1. `create_traced_graph()` monkey-patches `add_node()` to auto-wrap functions
|
|
209
|
+
2. `@traced` decorator publishes events to Redis Streams (1-2ms)
|
|
210
|
+
3. SwisperStudio consumer reads from stream and stores in database
|
|
211
|
+
4. Zero user-facing latency (fire-and-forget pattern)
|
|
212
|
+
|
|
213
|
+
## Configuration
|
|
214
|
+
|
|
215
|
+
### Required Settings
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
# In your config.py or .env
|
|
219
|
+
SWISPER_STUDIO_REDIS_URL: str = "redis://redis:6379"
|
|
220
|
+
SWISPER_STUDIO_PROJECT_ID: str = "your-project-id"
|
|
221
|
+
SWISPER_STUDIO_STREAM_NAME: str = "observability:events"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Optional Settings
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
# Reasoning capture
|
|
228
|
+
SWISPER_STUDIO_CAPTURE_REASONING: bool = True
|
|
229
|
+
SWISPER_STUDIO_REASONING_MAX_LENGTH: int = 50000 # 50 KB
|
|
230
|
+
|
|
231
|
+
# Connection verification
|
|
232
|
+
SWISPER_STUDIO_VERIFY_CONSUMER: bool = True # Check consumer health
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Requirements
|
|
236
|
+
|
|
237
|
+
- Python 3.11+
|
|
238
|
+
- LangGraph >= 1.0.0, < 2.0.0
|
|
239
|
+
- langgraph-checkpoint >= 2.1.0, < 3.0.0 (⚠️ Note: 3.0 has breaking changes)
|
|
240
|
+
- httpx >= 0.25.2
|
|
241
|
+
- redis >= 5.0.0
|
|
242
|
+
|
|
243
|
+
## Migration
|
|
244
|
+
|
|
245
|
+
Upgrading from v0.3.x? See [SDK_MIGRATION_v0.3.4_to_v0.4.0.md](../../SDK_MIGRATION_v0.3.4_to_v0.4.0.md)
|
|
246
|
+
|
|
247
|
+
**Migration time:** ~15 minutes
|
|
248
|
+
**Breaking changes:** None (backward compatible)
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT
|
|
253
|
+
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# SwisperStudio SDK
|
|
2
|
+
|
|
3
|
+
Simple, high-performance integration for tracing Swisper LangGraph applications.
|
|
4
|
+
|
|
5
|
+
**v0.4.0 - Redis Streams Architecture:**
|
|
6
|
+
- 🚀 **50x faster** - 500ms → 10ms overhead
|
|
7
|
+
- 🧠 **LLM reasoning** - See thinking process (`<think>...</think>`)
|
|
8
|
+
- 📡 **Connection status** - Heartbeat-based health monitoring
|
|
9
|
+
- ⚙️ **Per-node config** - Fine-grained control
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
### From PyPI (Recommended)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install swisper-studio-sdk==0.5.0
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
That's it! No authentication needed.
|
|
20
|
+
|
|
21
|
+
### From Source (Development)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/Fintama/swisper_studio.git
|
|
25
|
+
cd swisper_studio/sdk
|
|
26
|
+
pip install -e .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Note:** Source installation requires Fintama GitHub organization access.
|
|
30
|
+
|
|
31
|
+
## Quick Start (30 seconds)
|
|
32
|
+
|
|
33
|
+
### 1. Initialize at Startup (Redis Streams)
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# In your main.py or startup code
|
|
37
|
+
from swisper_studio_sdk import initialize_redis_publisher
|
|
38
|
+
|
|
39
|
+
# Async initialization (in lifespan or startup)
|
|
40
|
+
await initialize_redis_publisher(
|
|
41
|
+
redis_url="redis://redis:6379", # Your Redis instance
|
|
42
|
+
project_id="your-project-id", # From SwisperStudio
|
|
43
|
+
stream_name="observability:events", # Default stream name
|
|
44
|
+
verify_consumer=True, # Check SwisperStudio is running
|
|
45
|
+
)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. ONE LINE CHANGE to Enable Tracing
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
# Before:
|
|
52
|
+
from langgraph.graph import StateGraph
|
|
53
|
+
graph = StateGraph(GlobalSupervisorState)
|
|
54
|
+
|
|
55
|
+
# After (change ONE line):
|
|
56
|
+
from swisper_studio_sdk import create_traced_graph
|
|
57
|
+
graph = create_traced_graph(GlobalSupervisorState, trace_name="supervisor")
|
|
58
|
+
|
|
59
|
+
# That's it! All nodes added to this graph are automatically traced!
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. Add Nodes as Normal
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# Add nodes - they're automatically traced!
|
|
66
|
+
graph.add_node("intent_classification", intent_classification_node)
|
|
67
|
+
graph.add_node("memory", memory_node)
|
|
68
|
+
graph.add_node("planner", planner_node)
|
|
69
|
+
graph.add_node("ui_node", ui_node)
|
|
70
|
+
|
|
71
|
+
# Compile and run as usual
|
|
72
|
+
app = graph.compile()
|
|
73
|
+
result = await app.ainvoke(initial_state)
|
|
74
|
+
|
|
75
|
+
# All executions are now traced to SwisperStudio! 🎉
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Features
|
|
79
|
+
|
|
80
|
+
### **Core Features:**
|
|
81
|
+
- ✅ **One-line integration** - `create_traced_graph()` instead of `StateGraph()`
|
|
82
|
+
- ✅ **Auto-instrumentation** - All nodes automatically traced
|
|
83
|
+
- ✅ **State capture** - Captures input/output state at each node
|
|
84
|
+
- ✅ **Error tracking** - Captures exceptions and error messages
|
|
85
|
+
- ✅ **Nested observations** - Supports parent-child relationships
|
|
86
|
+
- ✅ **Zero boilerplate** - No decorators needed on individual nodes
|
|
87
|
+
|
|
88
|
+
### **v0.4.0 New Features:**
|
|
89
|
+
- ✅ **Redis Streams** - 50x faster than HTTP (500ms → 10ms)
|
|
90
|
+
- ✅ **LLM Reasoning** - Captures `<think>...</think>` tags from DeepSeek R1, o1, etc.
|
|
91
|
+
- ✅ **Streaming Support** - Captures full responses from streaming LLM calls
|
|
92
|
+
- ✅ **Connection Status** - Verifies SwisperStudio consumer is running
|
|
93
|
+
- ✅ **Per-Node Config** - Enable/disable reasoning per node
|
|
94
|
+
- ✅ **Memory Safety** - Auto-cleanup prevents memory leaks
|
|
95
|
+
|
|
96
|
+
## Advanced Usage
|
|
97
|
+
|
|
98
|
+
### LLM Reasoning Capture
|
|
99
|
+
|
|
100
|
+
Control reasoning capture per node:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from swisper_studio_sdk import traced
|
|
104
|
+
|
|
105
|
+
# Enable reasoning with custom length limit
|
|
106
|
+
@traced("classify_intent", capture_reasoning=True, reasoning_max_length=20000)
|
|
107
|
+
async def classify_intent_node(state):
|
|
108
|
+
# Captures <think>...</think> tags (up to 20KB)
|
|
109
|
+
return state
|
|
110
|
+
|
|
111
|
+
# Disable reasoning for specific nodes
|
|
112
|
+
@traced("memory_node", capture_reasoning=False)
|
|
113
|
+
async def memory_node(state):
|
|
114
|
+
# No reasoning captured (faster, less data)
|
|
115
|
+
return state
|
|
116
|
+
|
|
117
|
+
# Use defaults (reasoning enabled, 50KB limit)
|
|
118
|
+
@traced("global_planner")
|
|
119
|
+
async def global_planner_node(state):
|
|
120
|
+
return state
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**What gets captured:**
|
|
124
|
+
- ✅ LLM prompts (system + user messages)
|
|
125
|
+
- ✅ Reasoning process (`<think>...</think>` tags)
|
|
126
|
+
- ✅ Final responses (structured output or streaming)
|
|
127
|
+
- ✅ Token usage (prompt + completion)
|
|
128
|
+
|
|
129
|
+
**Supported models:**
|
|
130
|
+
- DeepSeek R1 (with reasoning)
|
|
131
|
+
- OpenAI o1/o3 (with reasoning)
|
|
132
|
+
- GPT-4, Claude, Llama (no reasoning, just prompts + responses)
|
|
133
|
+
|
|
134
|
+
### Manual Tracing (Optional)
|
|
135
|
+
|
|
136
|
+
For fine-grained control, use `@traced` decorator:
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from swisper_studio_sdk import traced
|
|
140
|
+
|
|
141
|
+
# Full control over observation
|
|
142
|
+
@traced(
|
|
143
|
+
name="intent_classification",
|
|
144
|
+
observation_type="GENERATION",
|
|
145
|
+
capture_reasoning=True,
|
|
146
|
+
reasoning_max_length=10000
|
|
147
|
+
)
|
|
148
|
+
async def intent_classification_node(state):
|
|
149
|
+
return state
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Observation Types
|
|
153
|
+
|
|
154
|
+
- `AUTO` - Auto-detect based on LLM data (default, recommended)
|
|
155
|
+
- `SPAN` - Generic execution span
|
|
156
|
+
- `GENERATION` - LLM generation
|
|
157
|
+
- `EVENT` - Point-in-time event
|
|
158
|
+
- `TOOL` - Tool call
|
|
159
|
+
- `AGENT` - Agent execution
|
|
160
|
+
|
|
161
|
+
## Architecture
|
|
162
|
+
|
|
163
|
+
### Redis Streams (v0.4.0)
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Your App (Swisper) Redis Stream SwisperStudio
|
|
167
|
+
│ │ │
|
|
168
|
+
@traced decorator │ │
|
|
169
|
+
│ │ │
|
|
170
|
+
XADD event (1-2ms) ──────────→ │ │
|
|
171
|
+
│ │ │
|
|
172
|
+
Return immediately │ │
|
|
173
|
+
(zero latency!) │ │
|
|
174
|
+
│ Consumer reads batch │
|
|
175
|
+
│ ←─────────────────────────┤
|
|
176
|
+
│ │
|
|
177
|
+
│ Store in PostgreSQL │
|
|
178
|
+
│ ──────────────────────────→
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Benefits:**
|
|
182
|
+
- **50x faster** than HTTP (500ms → 10ms overhead)
|
|
183
|
+
- **No race conditions** (ordered stream delivery)
|
|
184
|
+
- **Reliable** (persistent queue, automatic retry)
|
|
185
|
+
- **Scalable** (100k+ events/sec)
|
|
186
|
+
|
|
187
|
+
### How It Works
|
|
188
|
+
|
|
189
|
+
1. `create_traced_graph()` monkey-patches `add_node()` to auto-wrap functions
|
|
190
|
+
2. `@traced` decorator publishes events to Redis Streams (1-2ms)
|
|
191
|
+
3. SwisperStudio consumer reads from stream and stores in database
|
|
192
|
+
4. Zero user-facing latency (fire-and-forget pattern)
|
|
193
|
+
|
|
194
|
+
## Configuration
|
|
195
|
+
|
|
196
|
+
### Required Settings
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
# In your config.py or .env
|
|
200
|
+
SWISPER_STUDIO_REDIS_URL: str = "redis://redis:6379"
|
|
201
|
+
SWISPER_STUDIO_PROJECT_ID: str = "your-project-id"
|
|
202
|
+
SWISPER_STUDIO_STREAM_NAME: str = "observability:events"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Optional Settings
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
# Reasoning capture
|
|
209
|
+
SWISPER_STUDIO_CAPTURE_REASONING: bool = True
|
|
210
|
+
SWISPER_STUDIO_REASONING_MAX_LENGTH: int = 50000 # 50 KB
|
|
211
|
+
|
|
212
|
+
# Connection verification
|
|
213
|
+
SWISPER_STUDIO_VERIFY_CONSUMER: bool = True # Check consumer health
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Requirements
|
|
217
|
+
|
|
218
|
+
- Python 3.11+
|
|
219
|
+
- LangGraph >= 1.0.0, < 2.0.0
|
|
220
|
+
- langgraph-checkpoint >= 2.1.0, < 3.0.0 (⚠️ Note: 3.0 has breaking changes)
|
|
221
|
+
- httpx >= 0.25.2
|
|
222
|
+
- redis >= 5.0.0
|
|
223
|
+
|
|
224
|
+
## Migration
|
|
225
|
+
|
|
226
|
+
Upgrading from v0.3.x? See [SDK_MIGRATION_v0.3.4_to_v0.4.0.md](../../SDK_MIGRATION_v0.3.4_to_v0.4.0.md)
|
|
227
|
+
|
|
228
|
+
**Migration time:** ~15 minutes
|
|
229
|
+
**Breaking changes:** None (backward compatible)
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
MIT
|
|
234
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "swisper-studio-sdk"
|
|
3
|
+
version = "0.5.0"
|
|
4
|
+
description = "SwisperStudio SDK - Tracing integration for Swisper (internal use)"
|
|
5
|
+
authors = [{name = "Fintama SwisperStudio Team"}]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
license = {text = "Proprietary - Fintama Internal Use Only"}
|
|
9
|
+
dependencies = [
|
|
10
|
+
"httpx>=0.25.2",
|
|
11
|
+
"langgraph>=1.0.0,<2.0.0",
|
|
12
|
+
"langgraph-checkpoint>=2.1.0,<3.0.0",
|
|
13
|
+
"redis>=5.0.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://github.com/Fintama/swisper_studio"
|
|
18
|
+
Repository = "https://github.com/Fintama/swisper_studio"
|
|
19
|
+
Documentation = "https://github.com/Fintama/swisper_studio/tree/main/sdk"
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
dev = [
|
|
23
|
+
"pytest>=7.4.3",
|
|
24
|
+
"pytest-asyncio>=0.21.1",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[build-system]
|
|
28
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
29
|
+
build-backend = "setuptools.build_meta"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["."]
|
|
33
|
+
include = ["swisper_studio_sdk*"]
|
|
34
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SwisperStudio SDK
|
|
3
|
+
|
|
4
|
+
Simple integration for tracing Swisper LangGraph applications.
|
|
5
|
+
|
|
6
|
+
v0.5.0 - Q2 Tracing Toggle + Tool Observations:
|
|
7
|
+
- Dynamic tracing toggle (on/off per project)
|
|
8
|
+
- Universal tool observation extraction (no decorators!)
|
|
9
|
+
- Redis-cached toggle checks (<2ms overhead)
|
|
10
|
+
- Full cost tracking (316 models, CHF for KVANT)
|
|
11
|
+
- LLM reasoning capture
|
|
12
|
+
- 50x faster than HTTP (10ms overhead)
|
|
13
|
+
|
|
14
|
+
v0.4.0 - Redis Streams Architecture:
|
|
15
|
+
- 50x faster (500ms → 10ms overhead)
|
|
16
|
+
- LLM reasoning capture
|
|
17
|
+
- Connection status verification
|
|
18
|
+
- Per-node configuration
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
from swisper_studio_sdk import create_traced_graph, initialize_redis_publisher
|
|
22
|
+
|
|
23
|
+
# Initialize once at startup (async)
|
|
24
|
+
await initialize_redis_publisher(
|
|
25
|
+
redis_url="redis://redis:6379",
|
|
26
|
+
project_id="your-project-id",
|
|
27
|
+
stream_name="observability:events",
|
|
28
|
+
verify_consumer=True
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# One-line change to add tracing
|
|
32
|
+
graph = create_traced_graph(
|
|
33
|
+
GlobalSupervisorState,
|
|
34
|
+
trace_name="supervisor"
|
|
35
|
+
)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
# Define version BEFORE imports to avoid circular dependency
|
|
39
|
+
__version__ = "0.5.0" # Q2: Tracing toggle + universal tool observations
|
|
40
|
+
|
|
41
|
+
from swisper_studio_sdk.tracing.decorator import traced
|
|
42
|
+
from swisper_studio_sdk.tracing.graph_wrapper import create_traced_graph
|
|
43
|
+
from swisper_studio_sdk.tracing.client import initialize_tracing # Deprecated, use Redis
|
|
44
|
+
from swisper_studio_sdk.tracing.redis_publisher import initialize_redis_publisher, close_redis_publisher
|
|
45
|
+
from swisper_studio_sdk.wrappers import wrap_llm_adapter, wrap_tools
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"traced",
|
|
49
|
+
"create_traced_graph",
|
|
50
|
+
"initialize_tracing", # Deprecated - use initialize_redis_publisher
|
|
51
|
+
"initialize_redis_publisher",
|
|
52
|
+
"close_redis_publisher",
|
|
53
|
+
"wrap_llm_adapter",
|
|
54
|
+
"wrap_tools",
|
|
55
|
+
]
|
|
56
|
+
|