raysurfer 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.
- raysurfer/__init__.py +101 -0
- raysurfer/client.py +773 -0
- raysurfer/exceptions.py +21 -0
- raysurfer/sdk_client.py +552 -0
- raysurfer/sdk_types.py +30 -0
- raysurfer/types.py +198 -0
- raysurfer-0.4.1.dist-info/METADATA +157 -0
- raysurfer-0.4.1.dist-info/RECORD +9 -0
- raysurfer-0.4.1.dist-info/WHEEL +4 -0
raysurfer/types.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""RaySurfer SDK types - mirrors the backend API types"""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ExecutionState(str, Enum):
|
|
11
|
+
"""Technical execution outcome - NOT a quality judgment"""
|
|
12
|
+
|
|
13
|
+
COMPLETED = "completed"
|
|
14
|
+
ERRORED = "errored"
|
|
15
|
+
TIMED_OUT = "timed_out"
|
|
16
|
+
CANCELLED = "cancelled"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AgentVerdict(str, Enum):
|
|
20
|
+
"""Agent's judgment on whether an execution was useful"""
|
|
21
|
+
|
|
22
|
+
THUMBS_UP = "thumbs_up"
|
|
23
|
+
THUMBS_DOWN = "thumbs_down"
|
|
24
|
+
PENDING = "pending"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SnipsDesired(str, Enum):
|
|
28
|
+
"""Scope of private snippets for retrieval"""
|
|
29
|
+
|
|
30
|
+
COMPANY = "company" # Organization-level snippets (Team or Enterprise tier)
|
|
31
|
+
CLIENT = "client" # Client workspace snippets (Enterprise tier only)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CodeBlock(BaseModel):
|
|
35
|
+
"""A stored code block with metadata for semantic retrieval"""
|
|
36
|
+
|
|
37
|
+
id: str
|
|
38
|
+
name: str
|
|
39
|
+
description: str
|
|
40
|
+
source: str
|
|
41
|
+
entrypoint: str
|
|
42
|
+
input_schema: dict[str, Any] = Field(default_factory=dict)
|
|
43
|
+
output_schema: dict[str, Any] = Field(default_factory=dict)
|
|
44
|
+
language: str
|
|
45
|
+
language_version: str | None = None
|
|
46
|
+
dependencies: list[str] = Field(default_factory=list)
|
|
47
|
+
tags: list[str] = Field(default_factory=list)
|
|
48
|
+
capabilities: list[str] = Field(default_factory=list)
|
|
49
|
+
example_queries: list[str] | None = None
|
|
50
|
+
created_at: datetime | None = None
|
|
51
|
+
updated_at: datetime | None = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class ExecutionIO(BaseModel):
|
|
55
|
+
"""Stores the actual input/output data"""
|
|
56
|
+
|
|
57
|
+
input_data: dict[str, Any]
|
|
58
|
+
input_hash: str = ""
|
|
59
|
+
output_data: Any = None
|
|
60
|
+
output_hash: str = ""
|
|
61
|
+
output_type: str = "unknown"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class AgentReview(BaseModel):
|
|
65
|
+
"""Agent's assessment of whether an execution was useful"""
|
|
66
|
+
|
|
67
|
+
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
|
68
|
+
verdict: AgentVerdict
|
|
69
|
+
reasoning: str
|
|
70
|
+
what_worked: list[str] = Field(default_factory=list)
|
|
71
|
+
what_didnt_work: list[str] = Field(default_factory=list)
|
|
72
|
+
output_was_useful: bool
|
|
73
|
+
output_was_correct: bool
|
|
74
|
+
output_was_complete: bool
|
|
75
|
+
error_was_appropriate: bool | None = None
|
|
76
|
+
would_use_again: bool
|
|
77
|
+
suggested_improvements: list[str] = Field(default_factory=list)
|
|
78
|
+
required_workaround: bool = False
|
|
79
|
+
workaround_description: str | None = None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class ExecutionRecord(BaseModel):
|
|
83
|
+
"""Full execution trace"""
|
|
84
|
+
|
|
85
|
+
id: str
|
|
86
|
+
code_block_id: str
|
|
87
|
+
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
|
88
|
+
execution_state: ExecutionState
|
|
89
|
+
duration_ms: int
|
|
90
|
+
error_message: str | None = None
|
|
91
|
+
error_type: str | None = None
|
|
92
|
+
io: ExecutionIO
|
|
93
|
+
triggering_task: str
|
|
94
|
+
retrieval_score: float = 0.0
|
|
95
|
+
verdict: AgentVerdict = AgentVerdict.PENDING
|
|
96
|
+
review: AgentReview | None = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class BestMatch(BaseModel):
|
|
100
|
+
"""The best matching code block with full scoring"""
|
|
101
|
+
|
|
102
|
+
code_block: CodeBlock
|
|
103
|
+
combined_score: float
|
|
104
|
+
vector_score: float
|
|
105
|
+
verdict_score: float
|
|
106
|
+
error_resilience: float
|
|
107
|
+
thumbs_up: int
|
|
108
|
+
thumbs_down: int
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AlternativeCandidate(BaseModel):
|
|
112
|
+
"""An alternative candidate code block"""
|
|
113
|
+
|
|
114
|
+
code_block_id: str
|
|
115
|
+
name: str
|
|
116
|
+
combined_score: float
|
|
117
|
+
reason: str
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class FewShotExample(BaseModel):
|
|
121
|
+
"""A few-shot example for code generation"""
|
|
122
|
+
|
|
123
|
+
task: str
|
|
124
|
+
input_sample: dict[str, Any]
|
|
125
|
+
output_sample: Any
|
|
126
|
+
code_snippet: str
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class TaskPattern(BaseModel):
|
|
130
|
+
"""A proven task→code mapping"""
|
|
131
|
+
|
|
132
|
+
task_pattern: str
|
|
133
|
+
code_block_id: str
|
|
134
|
+
code_block_name: str
|
|
135
|
+
thumbs_up: int
|
|
136
|
+
thumbs_down: int
|
|
137
|
+
verdict_score: float
|
|
138
|
+
error_resilience: float
|
|
139
|
+
last_thumbs_up: datetime | None = None
|
|
140
|
+
last_thumbs_down: datetime | None = None
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Response types
|
|
144
|
+
class StoreCodeBlockResponse(BaseModel):
|
|
145
|
+
success: bool
|
|
146
|
+
code_block_id: str
|
|
147
|
+
embedding_id: str
|
|
148
|
+
message: str
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class StoreExecutionResponse(BaseModel):
|
|
152
|
+
success: bool
|
|
153
|
+
execution_id: str
|
|
154
|
+
pattern_updated: bool
|
|
155
|
+
message: str
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class RetrieveCodeBlockResponse(BaseModel):
|
|
159
|
+
code_blocks: list["CodeBlockMatch"]
|
|
160
|
+
total_found: int
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class CodeBlockMatch(BaseModel):
|
|
164
|
+
code_block: CodeBlock
|
|
165
|
+
score: float
|
|
166
|
+
verdict_score: float
|
|
167
|
+
thumbs_up: int
|
|
168
|
+
thumbs_down: int
|
|
169
|
+
recent_executions: list[ExecutionRecord] = Field(default_factory=list)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class RetrieveBestResponse(BaseModel):
|
|
173
|
+
best_match: BestMatch | None
|
|
174
|
+
alternative_candidates: list[AlternativeCandidate]
|
|
175
|
+
retrieval_confidence: str
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class FileWritten(BaseModel):
|
|
179
|
+
"""A file written during agent execution"""
|
|
180
|
+
|
|
181
|
+
path: str
|
|
182
|
+
content: str
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class SubmitExecutionResultRequest(BaseModel):
|
|
186
|
+
"""Raw execution result - backend handles all processing"""
|
|
187
|
+
|
|
188
|
+
task: str
|
|
189
|
+
files_written: list[FileWritten]
|
|
190
|
+
succeeded: bool
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class SubmitExecutionResultResponse(BaseModel):
|
|
194
|
+
"""Response from submitting execution result"""
|
|
195
|
+
|
|
196
|
+
success: bool
|
|
197
|
+
code_blocks_stored: int
|
|
198
|
+
message: str
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: raysurfer
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Drop-in replacement for Claude Agent SDK with automatic code caching - just swap your import
|
|
5
|
+
Project-URL: Homepage, https://raysurfer.com
|
|
6
|
+
Project-URL: Repository, https://github.com/raymondxu/raysurfer-python
|
|
7
|
+
Author: Raymond Xu
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: agents,ai,anthropic,claude,code-blocks,embeddings,retrieval
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: claude-agent-sdk>=0.1.0
|
|
20
|
+
Requires-Dist: httpx>=0.25.0
|
|
21
|
+
Requires-Dist: pydantic>=2.0.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# RaySurfer Python SDK
|
|
30
|
+
|
|
31
|
+
Drop-in replacement for Claude Agent SDK with automatic code caching. Same API, 20-30x faster.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install raysurfer
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
Swap `ClaudeSDKClient` for `RaysurferClient` - everything else stays the same:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
# from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
|
|
45
|
+
from raysurfer import RaysurferClient, RaysurferAgentOptions
|
|
46
|
+
|
|
47
|
+
options = RaysurferAgentOptions(
|
|
48
|
+
raysurfer_api_key="your-api-key",
|
|
49
|
+
allowed_tools=["Read", "Write", "Bash"],
|
|
50
|
+
model="claude-sonnet-4-20250514",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# async with ClaudeSDKClient(options) as client:
|
|
54
|
+
async with RaysurferClient(options) as client:
|
|
55
|
+
await client.query("Generate quarterly sales report")
|
|
56
|
+
async for msg in client.receive_response():
|
|
57
|
+
print(msg)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
That's it. Your agent now automatically:
|
|
61
|
+
- Pre-fetches relevant cached code before each task
|
|
62
|
+
- Injects proven code snippets into the system prompt
|
|
63
|
+
- Stores successful outputs for future reuse
|
|
64
|
+
|
|
65
|
+
## How It Works
|
|
66
|
+
|
|
67
|
+
1. **On `query()`**: Retrieves cached code blocks matching your task
|
|
68
|
+
2. **Downloads to sandbox**: Files ready for the agent to execute
|
|
69
|
+
3. **Injects into prompt**: Agent sees proven code snippets
|
|
70
|
+
4. **After success**: New code is cached for next time
|
|
71
|
+
|
|
72
|
+
**Measured Results:**
|
|
73
|
+
- Without RaySurfer: 34.2s, 11 iterations, 2 tool calls
|
|
74
|
+
- With RaySurfer: 1.4s, 1 iteration, 0 tool calls
|
|
75
|
+
- **Speedup: 24x faster**
|
|
76
|
+
|
|
77
|
+
## RaysurferAgentOptions
|
|
78
|
+
|
|
79
|
+
All `ClaudeAgentOptions` fields are supported, plus:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
RaysurferAgentOptions(
|
|
83
|
+
# Raysurfer-specific
|
|
84
|
+
raysurfer_api_key="your-api-key",
|
|
85
|
+
prefetch_count=5, # Code files to pre-fetch
|
|
86
|
+
min_verdict_score=0.3, # Quality threshold
|
|
87
|
+
|
|
88
|
+
# Standard Claude Agent SDK options
|
|
89
|
+
allowed_tools=["Read", "Write", "Bash"],
|
|
90
|
+
model="claude-sonnet-4-20250514",
|
|
91
|
+
system_prompt="You are helpful.",
|
|
92
|
+
permission_mode="acceptEdits",
|
|
93
|
+
# ... all other ClaudeAgentOptions
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Snippet Retrieval Scope
|
|
98
|
+
|
|
99
|
+
Control which snippets are retrieved using `public_snips` and `snips_desired`:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from raysurfer import RaysurferClient
|
|
103
|
+
|
|
104
|
+
# Include both public and company snippets
|
|
105
|
+
client = RaysurferClient(
|
|
106
|
+
options=options,
|
|
107
|
+
public_snips=True, # Include public/shared snippets
|
|
108
|
+
snips_desired="company", # Also include company-level snippets (Team/Enterprise)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Enterprise: Retrieve client-specific snippets only
|
|
112
|
+
client = RaysurferClient(
|
|
113
|
+
options=options,
|
|
114
|
+
snips_desired="client", # Client workspace snippets (Enterprise only)
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
| Configuration | Required Tier |
|
|
119
|
+
|--------------|---------------|
|
|
120
|
+
| `public_snips=True` only | FREE (default) |
|
|
121
|
+
| `snips_desired="company"` | TEAM or ENTERPRISE |
|
|
122
|
+
| `snips_desired="client"` | ENTERPRISE only |
|
|
123
|
+
|
|
124
|
+
## Low-Level API
|
|
125
|
+
|
|
126
|
+
For direct code block storage and retrieval:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from raysurfer import RaySurfer
|
|
130
|
+
|
|
131
|
+
rs = RaySurfer(api_key="your-api-key")
|
|
132
|
+
|
|
133
|
+
# Store a code block
|
|
134
|
+
rs.store_code_block(
|
|
135
|
+
name="fetch_weather",
|
|
136
|
+
source="def fetch_weather(city): ...",
|
|
137
|
+
entrypoint="fetch_weather",
|
|
138
|
+
language="python",
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Retrieve by task
|
|
142
|
+
results = rs.retrieve("get weather data")
|
|
143
|
+
for match in results.code_blocks:
|
|
144
|
+
print(f"{match.code_block.name}: {match.score}")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Verdict System
|
|
148
|
+
|
|
149
|
+
RaySurfer learns which code actually works through thumbs up/down verdicts:
|
|
150
|
+
- A technical error can be thumbs up (correct validation)
|
|
151
|
+
- A successful run can be thumbs down (useless output)
|
|
152
|
+
|
|
153
|
+
The system learns usefulness, not just whether code runs.
|
|
154
|
+
|
|
155
|
+
## Examples
|
|
156
|
+
|
|
157
|
+
See [examples/](./examples) for complete demos.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
raysurfer/__init__.py,sha256=T3RhatqdJg_bSOjBaS_TCcNfGeo0iTvqZAHGs3NeHxg,2355
|
|
2
|
+
raysurfer/client.py,sha256=i4K5YcSPiBv1pU65EE4vopE2DsvNWNb7-ao7QcM8B5o,27338
|
|
3
|
+
raysurfer/exceptions.py,sha256=3HIkH4OPMRWyceHxegeiL0mVXAIRgE55DT2YrkWVEwU,425
|
|
4
|
+
raysurfer/sdk_client.py,sha256=JNbqsLTKgy-J4Z6iCo1jfo-gYdkTq5f20sgoIDjondA,22207
|
|
5
|
+
raysurfer/sdk_types.py,sha256=obp1oF4_MlFsylpIdOICHChNeK3OgqQvr2aPkjr8FoI,775
|
|
6
|
+
raysurfer/types.py,sha256=BnA5lZu9mW9XaOLPW4f4PmYazpUQX9-joIGOeMWcmAQ,4910
|
|
7
|
+
raysurfer-0.4.1.dist-info/METADATA,sha256=8-XDU9sLK0oJB-qWKExnOIMoTCDc-TAlr3Iu-tLPHj8,4694
|
|
8
|
+
raysurfer-0.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
9
|
+
raysurfer-0.4.1.dist-info/RECORD,,
|