raysurfer 0.2.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.
@@ -0,0 +1,27 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.so
5
+ .Python
6
+ build/
7
+ develop-eggs/
8
+ dist/
9
+ downloads/
10
+ eggs/
11
+ .eggs/
12
+ lib/
13
+ lib64/
14
+ parts/
15
+ sdist/
16
+ var/
17
+ wheels/
18
+ *.egg-info/
19
+ .installed.cfg
20
+ *.egg
21
+ .env
22
+ .venv
23
+ env/
24
+ venv/
25
+ .pytest_cache/
26
+ .ruff_cache/
27
+ .mypy_cache/
@@ -0,0 +1,189 @@
1
+ # Raysurfer Python SDK
2
+
3
+ Python SDK for Raysurfer - code block caching and retrieval for AI agents with Claude Agent SDK integration.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install raysurfer
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### Basic Client (Store/Retrieve Code Blocks)
14
+
15
+ ```python
16
+ from raysurfer import AsyncRaySurfer
17
+
18
+ async with AsyncRaySurfer(api_key="rs_...") as client:
19
+ # Store a code block
20
+ result = await client.store_code_block(
21
+ name="GitHub User Fetcher",
22
+ source="def fetch_user(username): ...",
23
+ entrypoint="fetch_user",
24
+ language="python",
25
+ )
26
+
27
+ # Retrieve code blocks for a task
28
+ response = await client.retrieve(task="Fetch GitHub user data")
29
+ for match in response.code_blocks:
30
+ print(match.code_block.name, match.verdict_score)
31
+ ```
32
+
33
+ ### Claude Agent SDK Integration
34
+
35
+ ```python
36
+ from raysurfer import RaysurferClient, RaysurferAgentOptions
37
+
38
+ options = RaysurferAgentOptions(
39
+ raysurfer_api_key="rs_...",
40
+ allowed_tools=["Read", "Write", "Bash"],
41
+ system_prompt="You are a helpful assistant.",
42
+ model="claude-opus-4-5", # Default
43
+ )
44
+
45
+ async with RaysurferClient(options=options) as client:
46
+ # Pre-fetches code files, downloads to sandbox, injects into prompt
47
+ await client.query("Fetch user data from GitHub API")
48
+
49
+ # Agent sees code files in system prompt and can execute with Bash
50
+ async for msg in client.receive_response():
51
+ print(msg)
52
+ ```
53
+
54
+ ## RaysurferAgentOptions
55
+
56
+ Drop-in replacement options for `ClaudeAgentOptions` with Raysurfer-specific settings:
57
+
58
+ ```python
59
+ @dataclass
60
+ class RaysurferAgentOptions:
61
+ # Raysurfer-specific
62
+ raysurfer_api_key: str | None = None
63
+ raysurfer_base_url: str = "https://api.raysurfer.com"
64
+ prefetch_count: int = 5
65
+ min_verdict_score: float = 0.3
66
+ prefer_complete: bool = True
67
+ sandbox_dir: Path = ~/.raysurfer/sandbox
68
+
69
+ # Standard ClaudeAgentOptions (all passed through)
70
+ allowed_tools: list[str] | None = None
71
+ model: str = "claude-opus-4-5"
72
+ system_prompt: str | dict | None = None
73
+ sandbox: dict | None = None
74
+ # ... all other ClaudeAgentOptions fields
75
+ ```
76
+
77
+ ## How It Works
78
+
79
+ 1. **On `query()`**: RaysurferClient calls the backend to get relevant code files
80
+ 2. **Downloads to sandbox**: Files are written to `~/.raysurfer/sandbox/`
81
+ 3. **Injects into prompt**: Code snippets are added to the system prompt
82
+ 4. **Agent executes**: Agent can run the code using the Bash tool within the sandbox
83
+
84
+ ---
85
+
86
+ # Claude Agent SDK Python Reference
87
+
88
+ ## Core Classes
89
+
90
+ ### `ClaudeSDKClient`
91
+
92
+ ```python
93
+ async with ClaudeSDKClient(options=options) as client:
94
+ await client.query("Hello Claude")
95
+ async for message in client.receive_response():
96
+ print(message)
97
+ ```
98
+
99
+ ### `ClaudeAgentOptions`
100
+
101
+ ```python
102
+ ClaudeAgentOptions(
103
+ allowed_tools=["Read", "Write", "Bash"],
104
+ disallowed_tools=[],
105
+ permission_mode="acceptEdits", # or "default", "plan", "bypassPermissions"
106
+ system_prompt="You are helpful.",
107
+ model="claude-opus-4-5",
108
+ cwd="/path/to/project",
109
+ sandbox={"enabled": True},
110
+ max_turns=10,
111
+ # ... more options
112
+ )
113
+ ```
114
+
115
+ Key parameters:
116
+ - `allowed_tools`: Tools the agent can use
117
+ - `permission_mode`: How permissions are handled
118
+ - `model`: Claude model to use
119
+ - `sandbox`: Enable sandboxed execution
120
+ - `setting_sources`: `["user", "project", "local"]` to load CLAUDE.md files
121
+
122
+ ### `SandboxSettings`
123
+
124
+ ```python
125
+ sandbox={
126
+ "enabled": True,
127
+ "autoAllowBashIfSandboxed": True,
128
+ "excludedCommands": ["docker"],
129
+ "network": {
130
+ "allowLocalBinding": True,
131
+ }
132
+ }
133
+ ```
134
+
135
+ ## Message Types
136
+
137
+ ```python
138
+ from claude_agent_sdk import (
139
+ AssistantMessage,
140
+ TextBlock,
141
+ ToolUseBlock,
142
+ ResultMessage,
143
+ )
144
+
145
+ async for message in client.receive_response():
146
+ if isinstance(message, AssistantMessage):
147
+ for block in message.content:
148
+ if isinstance(block, TextBlock):
149
+ print(block.text)
150
+ elif isinstance(block, ToolUseBlock):
151
+ print(f"Using tool: {block.name}")
152
+ elif isinstance(message, ResultMessage):
153
+ print(f"Done! Cost: ${message.total_cost_usd}")
154
+ ```
155
+
156
+ ## Custom Tools
157
+
158
+ ```python
159
+ from claude_agent_sdk import tool, create_sdk_mcp_server
160
+
161
+ @tool("greet", "Greet a user", {"name": str})
162
+ async def greet(args):
163
+ return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}
164
+
165
+ server = create_sdk_mcp_server("my-tools", tools=[greet])
166
+
167
+ options = ClaudeAgentOptions(
168
+ mcp_servers={"tools": server},
169
+ allowed_tools=["mcp__tools__greet"],
170
+ )
171
+ ```
172
+
173
+ ## Error Handling
174
+
175
+ ```python
176
+ from claude_agent_sdk import (
177
+ CLINotFoundError,
178
+ ProcessError,
179
+ CLIConnectionError,
180
+ )
181
+
182
+ try:
183
+ async for message in query(prompt="Hello"):
184
+ print(message)
185
+ except CLINotFoundError:
186
+ print("Install Claude Code: npm install -g @anthropic-ai/claude-code")
187
+ except ProcessError as e:
188
+ print(f"Process failed: {e.exit_code}")
189
+ ```
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: raysurfer
3
+ Version: 0.2.0
4
+ Summary: Python SDK for RaySurfer - code block caching and retrieval for AI agents with Claude Agent SDK integration
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>=7.0.0; extra == 'dev'
25
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # RaySurfer Python SDK
29
+
30
+ Store and retrieve code blocks for AI agents with semantic search and verdict-aware scoring.
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ pip install raysurfer
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```python
41
+ from raysurfer import RaySurfer
42
+
43
+ rs = RaySurfer(api_key="your-api-key")
44
+
45
+ # Store a code block
46
+ result = rs.store_code_block(
47
+ name="fetch_weather",
48
+ source="""
49
+ def fetch_weather(city: str) -> dict:
50
+ import requests
51
+ resp = requests.get(f"https://api.weather.com/{city}")
52
+ return resp.json()
53
+ """,
54
+ entrypoint="fetch_weather",
55
+ language="python",
56
+ description="Fetches weather data for a city",
57
+ tags=["api", "weather"],
58
+ )
59
+ print(f"Stored: {result.code_block_id}")
60
+
61
+ # Retrieve code blocks by task
62
+ results = rs.retrieve("get weather data for a location")
63
+ for match in results.code_blocks:
64
+ print(f"{match.code_block.name}: {match.score}")
65
+
66
+ # Get the single best match with verdict-aware scoring
67
+ best = rs.retrieve_best("fetch current temperature")
68
+ if best.best_match:
69
+ print(f"Best: {best.best_match.code_block.name}")
70
+ print(f"Confidence: {best.retrieval_confidence}")
71
+ ```
72
+
73
+ ## Async Usage
74
+
75
+ ```python
76
+ from raysurfer import AsyncRaySurfer
77
+
78
+ async def main():
79
+ async with AsyncRaySurfer(api_key="your-api-key") as rs:
80
+ results = await rs.retrieve("parse JSON data")
81
+ print(results.code_blocks)
82
+ ```
83
+
84
+ ## Store Execution Records
85
+
86
+ Track how code blocks perform to improve future retrieval:
87
+
88
+ ```python
89
+ from raysurfer import RaySurfer, ExecutionState, AgentVerdict
90
+
91
+ rs = RaySurfer(api_key="your-api-key")
92
+
93
+ # After running a code block
94
+ rs.store_execution(
95
+ code_block_id="cb_xxx",
96
+ triggering_task="get weather for NYC",
97
+ input_data={"city": "NYC"},
98
+ output_data={"temp": 72, "conditions": "sunny"},
99
+ execution_state=ExecutionState.COMPLETED,
100
+ duration_ms=150,
101
+ verdict=AgentVerdict.THUMBS_UP,
102
+ )
103
+ ```
104
+
105
+ ## API Reference
106
+
107
+ ### `RaySurfer` / `AsyncRaySurfer`
108
+
109
+ **Store methods:**
110
+ - `store_code_block(...)` - Store a new code block
111
+ - `store_execution(...)` - Store an execution record with optional verdict
112
+
113
+ **Retrieve methods:**
114
+ - `retrieve(task)` - Semantic search for code blocks
115
+ - `retrieve_best(task)` - Get the single best match with scoring
116
+ - `get_few_shot_examples(task)` - Get examples for code generation
117
+ - `get_task_patterns(...)` - Get proven task→code mappings
118
+
119
+ ## Verdict System
120
+
121
+ RaySurfer uses thumbs up/down verdicts that are **independent** of execution state:
122
+ - A technical error can be thumbs up (correct validation behavior)
123
+ - A successful execution can be thumbs down (useless output)
124
+
125
+ This allows the system to learn which code blocks are actually *useful*, not just which ones run without errors.
@@ -0,0 +1,98 @@
1
+ # RaySurfer Python SDK
2
+
3
+ Store and retrieve code blocks for AI agents with semantic search and verdict-aware scoring.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install raysurfer
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from raysurfer import RaySurfer
15
+
16
+ rs = RaySurfer(api_key="your-api-key")
17
+
18
+ # Store a code block
19
+ result = rs.store_code_block(
20
+ name="fetch_weather",
21
+ source="""
22
+ def fetch_weather(city: str) -> dict:
23
+ import requests
24
+ resp = requests.get(f"https://api.weather.com/{city}")
25
+ return resp.json()
26
+ """,
27
+ entrypoint="fetch_weather",
28
+ language="python",
29
+ description="Fetches weather data for a city",
30
+ tags=["api", "weather"],
31
+ )
32
+ print(f"Stored: {result.code_block_id}")
33
+
34
+ # Retrieve code blocks by task
35
+ results = rs.retrieve("get weather data for a location")
36
+ for match in results.code_blocks:
37
+ print(f"{match.code_block.name}: {match.score}")
38
+
39
+ # Get the single best match with verdict-aware scoring
40
+ best = rs.retrieve_best("fetch current temperature")
41
+ if best.best_match:
42
+ print(f"Best: {best.best_match.code_block.name}")
43
+ print(f"Confidence: {best.retrieval_confidence}")
44
+ ```
45
+
46
+ ## Async Usage
47
+
48
+ ```python
49
+ from raysurfer import AsyncRaySurfer
50
+
51
+ async def main():
52
+ async with AsyncRaySurfer(api_key="your-api-key") as rs:
53
+ results = await rs.retrieve("parse JSON data")
54
+ print(results.code_blocks)
55
+ ```
56
+
57
+ ## Store Execution Records
58
+
59
+ Track how code blocks perform to improve future retrieval:
60
+
61
+ ```python
62
+ from raysurfer import RaySurfer, ExecutionState, AgentVerdict
63
+
64
+ rs = RaySurfer(api_key="your-api-key")
65
+
66
+ # After running a code block
67
+ rs.store_execution(
68
+ code_block_id="cb_xxx",
69
+ triggering_task="get weather for NYC",
70
+ input_data={"city": "NYC"},
71
+ output_data={"temp": 72, "conditions": "sunny"},
72
+ execution_state=ExecutionState.COMPLETED,
73
+ duration_ms=150,
74
+ verdict=AgentVerdict.THUMBS_UP,
75
+ )
76
+ ```
77
+
78
+ ## API Reference
79
+
80
+ ### `RaySurfer` / `AsyncRaySurfer`
81
+
82
+ **Store methods:**
83
+ - `store_code_block(...)` - Store a new code block
84
+ - `store_execution(...)` - Store an execution record with optional verdict
85
+
86
+ **Retrieve methods:**
87
+ - `retrieve(task)` - Semantic search for code blocks
88
+ - `retrieve_best(task)` - Get the single best match with scoring
89
+ - `get_few_shot_examples(task)` - Get examples for code generation
90
+ - `get_task_patterns(...)` - Get proven task→code mappings
91
+
92
+ ## Verdict System
93
+
94
+ RaySurfer uses thumbs up/down verdicts that are **independent** of execution state:
95
+ - A technical error can be thumbs up (correct validation behavior)
96
+ - A successful execution can be thumbs down (useless output)
97
+
98
+ This allows the system to learn which code blocks are actually *useful*, not just which ones run without errors.
@@ -0,0 +1,54 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "raysurfer"
7
+ version = "0.2.0"
8
+ description = "Python SDK for RaySurfer - code block caching and retrieval for AI agents with Claude Agent SDK integration"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Raymond Xu" }
14
+ ]
15
+ keywords = ["ai", "agents", "code-blocks", "retrieval", "embeddings", "claude", "anthropic"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ ]
26
+ dependencies = [
27
+ "httpx>=0.25.0",
28
+ "pydantic>=2.0.0",
29
+ "claude-agent-sdk>=0.1.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=7.0.0",
35
+ "pytest-asyncio>=0.21.0",
36
+ "ruff>=0.1.0",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://raysurfer.com"
41
+ Repository = "https://github.com/raymondxu/raysurfer-python"
42
+
43
+ [tool.hatch.build.targets.wheel]
44
+ packages = ["src/raysurfer"]
45
+
46
+ [tool.ruff]
47
+ line-length = 100
48
+ target-version = "py310"
49
+
50
+ [tool.ruff.lint]
51
+ select = ["E", "F", "I", "W"]
52
+
53
+ [tool.pytest.ini_options]
54
+ asyncio_mode = "auto"
@@ -0,0 +1,51 @@
1
+ """
2
+ RaySurfer Python SDK
3
+
4
+ Store and retrieve code blocks for AI agents with semantic search
5
+ and verdict-aware scoring.
6
+
7
+ Includes Claude Agent SDK integration via RaysurferClient.
8
+ """
9
+
10
+ from raysurfer.client import RaySurfer, AsyncRaySurfer
11
+ from raysurfer.sdk_client import RaysurferClient, RaysurferAgentOptions
12
+ from raysurfer.types import (
13
+ AgentReview,
14
+ AgentVerdict,
15
+ BestMatch,
16
+ CodeBlock,
17
+ ExecutionIO,
18
+ ExecutionRecord,
19
+ ExecutionState,
20
+ FewShotExample,
21
+ TaskPattern,
22
+ )
23
+ from raysurfer.sdk_types import CodeFile, GetCodeFilesResponse
24
+ from raysurfer.exceptions import RaySurferError, APIError, AuthenticationError
25
+
26
+ __version__ = "0.2.0"
27
+
28
+ __all__ = [
29
+ # Clients
30
+ "RaySurfer",
31
+ "AsyncRaySurfer",
32
+ # Claude Agent SDK integration
33
+ "RaysurferClient",
34
+ "RaysurferAgentOptions",
35
+ # Types
36
+ "AgentReview",
37
+ "AgentVerdict",
38
+ "BestMatch",
39
+ "CodeBlock",
40
+ "CodeFile",
41
+ "ExecutionIO",
42
+ "ExecutionRecord",
43
+ "ExecutionState",
44
+ "FewShotExample",
45
+ "GetCodeFilesResponse",
46
+ "TaskPattern",
47
+ # Exceptions
48
+ "RaySurferError",
49
+ "APIError",
50
+ "AuthenticationError",
51
+ ]