Skip to content

Commit d12e1c9

Browse files
Gameli LadzekpoGameli Ladzekpo
authored andcommitted
Initial release v0.1.0 - Published to PyPI
0 parents  commit d12e1c9

File tree

11 files changed

+1971
-0
lines changed

11 files changed

+1971
-0
lines changed

.gitignore

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
pip-wheel-metadata/
24+
share/python-wheels/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
MANIFEST
29+
30+
# PyInstaller
31+
*.manifest
32+
*.spec
33+
34+
# Unit test / coverage reports
35+
htmlcov/
36+
.tox/
37+
.nox/
38+
.coverage
39+
.coverage.*
40+
.cache
41+
nosetests.xml
42+
coverage.xml
43+
*.cover
44+
*.py,cover
45+
.hypothesis/
46+
.pytest_cache/
47+
48+
# Environments
49+
.env
50+
.venv
51+
env/
52+
venv/
53+
ENV/
54+
env.bak/
55+
venv.bak/
56+
57+
# IDEs
58+
.vscode/
59+
.idea/
60+
*.swp
61+
*.swo
62+
*~
63+
64+
# mypy
65+
.mypy_cache/
66+
.dmypy.json
67+
dmypy.json
68+
69+
# Pyre type checker
70+
.pyre/
71+
72+
# pytype static type analyzer
73+
.pytype/
74+
75+
# OS
76+
.DS_Store
77+
Thumbs.db

README.md

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# Surfa Ingest SDK
2+
3+
[![PyPI version](https://badge.fury.io/py/surfa-ingest.svg)](https://badge.fury.io/py/surfa-ingest)
4+
[![Python Support](https://img.shields.io/pypi/pyversions/surfa-ingest.svg)](https://pypi.org/project/surfa-ingest/)
5+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6+
[![Downloads](https://pepy.tech/badge/surfa-ingest)](https://pepy.tech/project/surfa-ingest)
7+
8+
Official Python SDK for ingesting live traffic events to Surfa Analytics.
9+
10+
## Features
11+
12+
- 🚀 **Event Buffering** - Automatic batching with configurable buffer size
13+
- 🔄 **Auto-Retry** - Built-in retry logic with exponential backoff
14+
- 📦 **Context Manager** - Automatic session lifecycle management
15+
- 🏷️ **Runtime Metadata** - Track AI provider, model, and configuration
16+
-**Event Validation** - Client-side validation before sending
17+
- 🔍 **Correlation IDs** - Link related events together
18+
- 📊 **Session Tracking** - Automatic session ID generation
19+
- 🛡️ **Type Safety** - Full type hints and IDE autocomplete
20+
21+
## Installation
22+
23+
```bash
24+
pip install surfa-ingest
25+
```
26+
27+
## Quick Start
28+
29+
```python
30+
from surfa_ingest import SurfaClient
31+
32+
# Initialize client with your ingest key
33+
client = SurfaClient(ingest_key="sk_live_your_key_here")
34+
35+
# Track events
36+
client.track({
37+
"kind": "tool",
38+
"subtype": "call_started",
39+
"tool_name": "search_web",
40+
"args": {"query": "AI news"}
41+
})
42+
43+
client.track({
44+
"kind": "tool",
45+
"subtype": "call_completed",
46+
"tool_name": "search_web",
47+
"status": "success",
48+
"latency_ms": 234
49+
})
50+
51+
# Flush events to API
52+
client.flush()
53+
```
54+
55+
## Context Manager (Recommended)
56+
57+
Use the context manager to automatically track session lifecycle:
58+
59+
```python
60+
from surfa_ingest import SurfaClient
61+
62+
with SurfaClient(ingest_key="sk_live_your_key_here") as client:
63+
# Session automatically started
64+
65+
client.track({
66+
"kind": "tool",
67+
"subtype": "call_started",
68+
"tool_name": "search_web"
69+
})
70+
71+
# Session automatically ended and events flushed on exit
72+
```
73+
74+
## Configuration
75+
76+
```python
77+
client = SurfaClient(
78+
ingest_key="sk_live_your_key_here",
79+
api_url="https://api.surfa.dev", # Default: http://localhost:3000
80+
flush_at=25, # Auto-flush after 25 events
81+
timeout_s=10, # HTTP timeout in seconds
82+
)
83+
```
84+
85+
## Set Runtime Metadata
86+
87+
Track which AI runtime is being used:
88+
89+
```python
90+
client = SurfaClient(ingest_key="sk_live_...")
91+
92+
client.set_runtime(
93+
provider="anthropic",
94+
model="claude-sonnet-4-5",
95+
mode="messages"
96+
)
97+
```
98+
99+
## Event Types
100+
101+
### Tool Events
102+
103+
```python
104+
# Tool call started
105+
client.track({
106+
"kind": "tool",
107+
"subtype": "call_started",
108+
"tool_name": "search_web",
109+
"direction": "request",
110+
"args": {"query": "Python tutorials"}
111+
})
112+
113+
# Tool call completed
114+
client.track({
115+
"kind": "tool",
116+
"subtype": "call_completed",
117+
"tool_name": "search_web",
118+
"direction": "response",
119+
"status": "success",
120+
"latency_ms": 234,
121+
"results": [{"title": "Learn Python", "url": "..."}]
122+
})
123+
```
124+
125+
### Session Events
126+
127+
```python
128+
# Session started
129+
client.session_started()
130+
131+
# Session ended
132+
client.session_ended()
133+
```
134+
135+
### Runtime Events
136+
137+
```python
138+
# LLM request
139+
client.track({
140+
"kind": "runtime",
141+
"subtype": "llm_request",
142+
"direction": "outbound",
143+
"messages": [{"role": "user", "content": "Hello"}],
144+
"temperature": 0.7
145+
})
146+
```
147+
148+
## Event Fields
149+
150+
### Required Fields
151+
- `kind` (str): Event type (e.g., "tool", "session", "runtime")
152+
153+
### Optional Fields
154+
- `subtype` (str): Event subtype (e.g., "call_started", "session_ended")
155+
- `tool_name` (str): Name of the tool
156+
- `status` (str): Status (e.g., "success", "error")
157+
- `direction` (str): Direction (e.g., "request", "response")
158+
- `method` (str): HTTP method or similar
159+
- `correlation_id` (str): Correlation ID for pairing events
160+
- `span_parent_id` (str): Parent span ID for tracing
161+
- `latency_ms` (int): Latency in milliseconds
162+
- `ts` (str): Timestamp (ISO 8601 format, auto-generated if not provided)
163+
- Any additional fields will be included in the event payload
164+
165+
## Auto-Flush
166+
167+
Events are automatically flushed when:
168+
1. Buffer reaches `flush_at` events (default: 25)
169+
2. Context manager exits
170+
3. `flush()` is called explicitly
171+
172+
## Error Handling
173+
174+
```python
175+
from surfa_ingest import SurfaClient, SurfaConfigError, SurfaValidationError
176+
177+
try:
178+
client = SurfaClient(ingest_key="invalid_key")
179+
except SurfaConfigError as e:
180+
print(f"Configuration error: {e}")
181+
182+
try:
183+
client.track({"invalid": "event"}) # Missing 'kind'
184+
except SurfaValidationError as e:
185+
print(f"Validation error: {e}")
186+
```
187+
188+
## Logging
189+
190+
The SDK uses Python's standard logging module:
191+
192+
```python
193+
import logging
194+
195+
logging.basicConfig(level=logging.DEBUG)
196+
logger = logging.getLogger("surfa_ingest")
197+
```
198+
199+
## Development Status
200+
201+
**Current Version: 0.1.0 (Alpha)**
202+
203+
This SDK is in active development. The API may change in future versions.
204+
205+
### Implemented
206+
- ✅ Client initialization
207+
- ✅ Event buffering
208+
- ✅ Session management
209+
- ✅ Context manager support
210+
- ✅ Event validation
211+
- ✅ Runtime metadata
212+
- ✅ HTTP API integration
213+
- ✅ Automatic retry logic (3 retries with exponential backoff)
214+
215+
### Coming Soon
216+
- 🔜 Background flushing
217+
- 🔜 Async support
218+
219+
## License
220+
221+
MIT
222+
223+
## Links
224+
225+
- 📦 **PyPI**: https://pypi.org/project/surfa-ingest/
226+
- 📚 **Documentation**: https://docs.surfa.dev
227+
- 🐛 **Issues**: https://github.com/gamladz/surfa/issues
228+
- 💬 **Discussions**: https://github.com/gamladz/surfa/discussions
229+
230+
## Contributing
231+
232+
Contributions are welcome! Please feel free to submit a Pull Request.
233+
234+
## Changelog
235+
236+
### 0.1.0 (2026-02-20)
237+
238+
- Initial release
239+
- Event buffering and batching
240+
- Session management
241+
- Context manager support
242+
- Runtime metadata capture
243+
- HTTP API integration with retry logic
244+
- Event validation

0 commit comments

Comments
 (0)