raysurfer 0.5.11 → 0.5.12
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.
- package/README.md +228 -68
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# RaySurfer TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
LLM output caching for AI agents. Retrieve proven code instead of
|
|
4
|
+
regenerating it.
|
|
4
5
|
|
|
5
6
|
## Installation
|
|
6
7
|
|
|
@@ -16,9 +17,221 @@ Set your API key:
|
|
|
16
17
|
export RAYSURFER_API_KEY=your_api_key_here
|
|
17
18
|
```
|
|
18
19
|
|
|
19
|
-
Get your key from the
|
|
20
|
+
Get your key from the
|
|
21
|
+
[dashboard](https://raysurfer.com/dashboard/api-keys).
|
|
20
22
|
|
|
21
|
-
##
|
|
23
|
+
## Low-Level API
|
|
24
|
+
|
|
25
|
+
For custom integrations, use the `RaySurfer` client directly with
|
|
26
|
+
any LLM provider.
|
|
27
|
+
|
|
28
|
+
### Complete Example
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { RaySurfer } from "raysurfer";
|
|
32
|
+
|
|
33
|
+
const client = new RaySurfer({ apiKey: "your_api_key" });
|
|
34
|
+
const task = "Fetch GitHub trending repos";
|
|
35
|
+
|
|
36
|
+
// 1. Retrieve cached code files for a task
|
|
37
|
+
const result = await client.getCodeFiles({
|
|
38
|
+
task,
|
|
39
|
+
topK: 5,
|
|
40
|
+
minVerdictScore: 0.3,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// result.addToLlmPrompt contains a pre-formatted string like:
|
|
44
|
+
//
|
|
45
|
+
// You have access to pre-written code files:
|
|
46
|
+
// - .raysurfer_code/github_fetcher.ts: Fetches trending repos
|
|
47
|
+
// ...
|
|
48
|
+
|
|
49
|
+
// Augment your system prompt with cached code context
|
|
50
|
+
const basePrompt = "You are a helpful coding assistant.";
|
|
51
|
+
const augmentedPrompt = basePrompt + result.addToLlmPrompt;
|
|
52
|
+
|
|
53
|
+
// Use augmentedPrompt with any LLM provider (Anthropic, OpenAI, etc.)
|
|
54
|
+
|
|
55
|
+
// 2. Upload a new code file after execution
|
|
56
|
+
await client.uploadNewCodeSnip({
|
|
57
|
+
task,
|
|
58
|
+
fileWritten: {
|
|
59
|
+
path: "fetch_repos.ts",
|
|
60
|
+
content: "function fetch() { ... }",
|
|
61
|
+
},
|
|
62
|
+
succeeded: true,
|
|
63
|
+
executionLogs: "Fetched 10 trending repos successfully",
|
|
64
|
+
dependencies: { "node-fetch": "3.3.0", zod: "3.22.0" },
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// 2b. Bulk upload prompts/logs/code for sandboxed grading
|
|
68
|
+
await client.uploadBulkCodeSnips(
|
|
69
|
+
["Build a CLI tool", "Add CSV support"],
|
|
70
|
+
[{ path: "cli.ts", content: "function main() { ... }" }],
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
path: "logs/run.log",
|
|
74
|
+
content: "Task completed",
|
|
75
|
+
encoding: "utf-8",
|
|
76
|
+
},
|
|
77
|
+
]
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// 3. Vote on whether a cached snippet was useful
|
|
81
|
+
await client.voteCodeSnip({
|
|
82
|
+
task,
|
|
83
|
+
codeBlockId: result.files[0].codeBlockId,
|
|
84
|
+
codeBlockName: result.files[0].filename,
|
|
85
|
+
codeBlockDescription: result.files[0].description,
|
|
86
|
+
succeeded: true,
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Client Options
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const client = new RaySurfer({
|
|
94
|
+
apiKey: "your_api_key",
|
|
95
|
+
baseUrl: "https://api.raysurfer.com", // optional
|
|
96
|
+
timeout: 30000, // optional, in ms
|
|
97
|
+
organizationId: "org_xxx", // optional, for team namespacing
|
|
98
|
+
workspaceId: "ws_xxx", // optional, for enterprise namespacing
|
|
99
|
+
snipsDesired: "company", // optional, snippet scope
|
|
100
|
+
publicSnips: true, // optional, include community snippets
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Response Fields
|
|
105
|
+
|
|
106
|
+
The `getCodeFiles()` response includes:
|
|
107
|
+
|
|
108
|
+
| Field | Type | Description |
|
|
109
|
+
| ---------------- | ------------ | --------------------------------- |
|
|
110
|
+
| `files` | `CodeFile[]` | Retrieved code files with metadata|
|
|
111
|
+
| `task` | `string` | The task that was searched |
|
|
112
|
+
| `totalFound` | `number` | Total matches found |
|
|
113
|
+
| `addToLlmPrompt` | `string` | Pre-formatted string to append to LLM system prompt |
|
|
114
|
+
|
|
115
|
+
Each `CodeFile` contains `codeBlockId`, `filename`, `source`,
|
|
116
|
+
`description`, `verdictScore`, `thumbsUp`, `thumbsDown`, and
|
|
117
|
+
`similarityScore`.
|
|
118
|
+
|
|
119
|
+
### Store a Code Block with Full Metadata
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const result = await client.storeCodeBlock({
|
|
123
|
+
name: "GitHub User Fetcher",
|
|
124
|
+
source: "function fetchUser(username) { ... }",
|
|
125
|
+
entrypoint: "fetchUser",
|
|
126
|
+
language: "typescript",
|
|
127
|
+
description: "Fetches user data from GitHub API",
|
|
128
|
+
tags: ["github", "api", "user"],
|
|
129
|
+
dependencies: { "node-fetch": "3.3.0" },
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Retrieve Few-Shot Examples
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const examples = await client.getFewShotExamples(
|
|
137
|
+
"Parse CSV files",
|
|
138
|
+
3
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
for (const ex of examples) {
|
|
142
|
+
console.log(`Task: ${ex.task}`);
|
|
143
|
+
console.log(`Code: ${ex.codeSnippet}`);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Retrieve Task Patterns
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const patterns = await client.getTaskPatterns({
|
|
151
|
+
task: "API integration",
|
|
152
|
+
minThumbsUp: 5,
|
|
153
|
+
topK: 20,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
for (const p of patterns) {
|
|
157
|
+
console.log(`${p.taskPattern} -> ${p.codeBlockName}`);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### User-Provided Votes
|
|
162
|
+
|
|
163
|
+
Instead of relying on AI voting, provide your own votes:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// Single upload with your own vote (AI voting is skipped)
|
|
167
|
+
await client.uploadNewCodeSnip({
|
|
168
|
+
task: "Fetch GitHub trending repos",
|
|
169
|
+
fileWritten: file,
|
|
170
|
+
succeeded: true,
|
|
171
|
+
userVote: 1, // 1 = thumbs up, -1 = thumbs down
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Bulk upload with per-file votes (AI grading is skipped)
|
|
175
|
+
await client.uploadBulkCodeSnips(
|
|
176
|
+
["Build a CLI tool", "Add CSV support"],
|
|
177
|
+
files,
|
|
178
|
+
logs,
|
|
179
|
+
true, // useRaysurferAiVoting (ignored when userVotes set)
|
|
180
|
+
{ "app.ts": 1, "utils.ts": -1 } // userVotes
|
|
181
|
+
);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Method Reference
|
|
185
|
+
|
|
186
|
+
| Method | Description |
|
|
187
|
+
|--------|-------------|
|
|
188
|
+
| `search({ task, topK?, minVerdictScore?, preferComplete?, inputSchema? })` | Unified search for cached code (recommended) |
|
|
189
|
+
| `getCodeFiles({ task, topK?, minVerdictScore?, preferComplete?, cacheDir? })` | Retrieve cached code files with `addToLlmPrompt` for LLM augmentation |
|
|
190
|
+
| `getCodeSnips({ task, topK?, minVerdictScore? })` | Retrieve cached code snippets by semantic search |
|
|
191
|
+
| `retrieveBest({ task, topK?, minVerdictScore? })` | Retrieve the single best match |
|
|
192
|
+
| `getFewShotExamples(task, k)` | Retrieve few-shot examples for code generation prompting |
|
|
193
|
+
| `getTaskPatterns({ task, minThumbsUp?, topK? })` | Retrieve proven task-to-code mappings |
|
|
194
|
+
| `storeCodeBlock({ name, source, entrypoint, language, description, tags?, dependencies?, ... })` | Store a code block with full metadata |
|
|
195
|
+
| `uploadNewCodeSnip({ task, fileWritten, succeeded, useRaysurferAiVoting?, userVote?, executionLogs?, dependencies? })` | Store a single code file with optional dependency versions |
|
|
196
|
+
| `uploadBulkCodeSnips(prompts, filesWritten, logFiles?, useRaysurferAiVoting?, userVotes?)` | Bulk upload for grading (AI votes by default, or provide per-file votes) |
|
|
197
|
+
| `voteCodeSnip({ task, codeBlockId, codeBlockName, codeBlockDescription, succeeded })` | Vote on snippet usefulness |
|
|
198
|
+
|
|
199
|
+
### Exceptions
|
|
200
|
+
|
|
201
|
+
Both clients include built-in retry logic with exponential backoff
|
|
202
|
+
for transient failures (429, 5xx, network errors).
|
|
203
|
+
|
|
204
|
+
| Exception | Description |
|
|
205
|
+
| ----------------------- | ---------------------------------------------------- |
|
|
206
|
+
| `RaySurferError` | Base exception for all Raysurfer errors |
|
|
207
|
+
| `APIError` | API returned an error response (includes `statusCode`) |
|
|
208
|
+
| `AuthenticationError` | API key is invalid or missing |
|
|
209
|
+
| `CacheUnavailableError` | Cache backend is unreachable |
|
|
210
|
+
| `RateLimitError` | Rate limit exceeded after retries (includes `retryAfter`) |
|
|
211
|
+
| `ValidationError` | Request validation failed (includes `field`) |
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { RaySurfer, RateLimitError } from "raysurfer";
|
|
215
|
+
|
|
216
|
+
const client = new RaySurfer({ apiKey: "your_api_key" });
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const result = await client.getCodeSnips({
|
|
220
|
+
task: "Fetch GitHub repos",
|
|
221
|
+
});
|
|
222
|
+
} catch (e) {
|
|
223
|
+
if (e instanceof RateLimitError) {
|
|
224
|
+
console.log(`Rate limited after retries: ${e.message}`);
|
|
225
|
+
if (e.retryAfter) {
|
|
226
|
+
console.log(`Try again in ${e.retryAfter}ms`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Claude Agent SDK Drop-in
|
|
22
235
|
|
|
23
236
|
Swap your import — everything else stays the same:
|
|
24
237
|
|
|
@@ -40,8 +253,8 @@ for await (const message of query({
|
|
|
40
253
|
}
|
|
41
254
|
```
|
|
42
255
|
|
|
43
|
-
All Claude SDK types are re-exported from `raysurfer`, so you don't
|
|
44
|
-
separate import:
|
|
256
|
+
All Claude SDK types are re-exported from `raysurfer`, so you don't
|
|
257
|
+
need a separate import:
|
|
45
258
|
|
|
46
259
|
```typescript
|
|
47
260
|
import {
|
|
@@ -52,16 +265,7 @@ import {
|
|
|
52
265
|
} from "raysurfer";
|
|
53
266
|
```
|
|
54
267
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
1. **On query**: Retrieves cached code blocks matching your task
|
|
58
|
-
2. **Injects into prompt**: Agent sees proven code snippets
|
|
59
|
-
3. **After success**: New code is cached for next time
|
|
60
|
-
|
|
61
|
-
Caching is enabled automatically when `RAYSURFER_API_KEY` is set. Without it,
|
|
62
|
-
behaves exactly like the original SDK.
|
|
63
|
-
|
|
64
|
-
## Class-based API
|
|
268
|
+
### Class-based API
|
|
65
269
|
|
|
66
270
|
```typescript
|
|
67
271
|
import { ClaudeSDKClient } from "raysurfer";
|
|
@@ -76,7 +280,7 @@ for await (const msg of client.query("Fetch data from GitHub API")) {
|
|
|
76
280
|
}
|
|
77
281
|
```
|
|
78
282
|
|
|
79
|
-
|
|
283
|
+
### System Prompt Preset
|
|
80
284
|
|
|
81
285
|
Use the Claude Code preset system prompt with appended instructions:
|
|
82
286
|
|
|
@@ -95,9 +299,10 @@ for await (const message of query({
|
|
|
95
299
|
}
|
|
96
300
|
```
|
|
97
301
|
|
|
98
|
-
|
|
302
|
+
### Query Control Methods
|
|
99
303
|
|
|
100
|
-
The `query()` function returns a `Query` object with full control
|
|
304
|
+
The `query()` function returns a `Query` object with full control
|
|
305
|
+
methods:
|
|
101
306
|
|
|
102
307
|
```typescript
|
|
103
308
|
const q = query({ prompt: "Build a REST API" });
|
|
@@ -111,6 +316,11 @@ const info = await q.accountInfo();
|
|
|
111
316
|
q.close();
|
|
112
317
|
```
|
|
113
318
|
|
|
319
|
+
### Without Caching
|
|
320
|
+
|
|
321
|
+
If `RAYSURFER_API_KEY` is not set, behaves exactly like the original
|
|
322
|
+
SDK — no caching, just a pass-through wrapper.
|
|
323
|
+
|
|
114
324
|
## Snippet Retrieval Scope
|
|
115
325
|
|
|
116
326
|
Control which cached snippets are retrieved:
|
|
@@ -148,56 +358,6 @@ const client = new ClaudeSDKClient({ publicSnips: true });
|
|
|
148
358
|
const rs = new RaySurfer({ apiKey: "...", publicSnips: true });
|
|
149
359
|
```
|
|
150
360
|
|
|
151
|
-
## Low-Level API
|
|
152
|
-
|
|
153
|
-
For custom integrations, use the `RaySurfer` client directly:
|
|
154
|
-
|
|
155
|
-
```typescript
|
|
156
|
-
import { RaySurfer } from "raysurfer";
|
|
157
|
-
|
|
158
|
-
const client = new RaySurfer({ apiKey: "your_api_key" });
|
|
159
|
-
|
|
160
|
-
// 1. Get cached code snippets for a task
|
|
161
|
-
const snips = await client.getCodeSnips({
|
|
162
|
-
task: "Fetch GitHub trending repos",
|
|
163
|
-
});
|
|
164
|
-
for (const match of snips.codeBlocks) {
|
|
165
|
-
console.log(`${match.codeBlock.name}: ${match.score}`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Or use the unified search endpoint
|
|
169
|
-
const searchResult = await client.search({
|
|
170
|
-
task: "Fetch GitHub trending repos",
|
|
171
|
-
});
|
|
172
|
-
for (const match of searchResult.matches) {
|
|
173
|
-
console.log(`${match.codeBlock.name}: ${match.combinedScore}`);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// 2. Upload a new code file after execution
|
|
177
|
-
await client.uploadNewCodeSnip(
|
|
178
|
-
"Fetch GitHub trending repos",
|
|
179
|
-
{ path: "fetch_repos.ts", content: "function fetch() { ... }" },
|
|
180
|
-
true // succeeded
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
// 2b. Bulk upload prompts/logs/code for sandboxed grading
|
|
184
|
-
await client.uploadBulkCodeSnips(
|
|
185
|
-
["Build a CLI tool", "Add CSV support"],
|
|
186
|
-
[{ path: "cli.ts", content: "function main() { ... }" }],
|
|
187
|
-
[{ path: "logs/run.log", content: "Task completed", encoding: "utf-8" }],
|
|
188
|
-
true
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
// 3. Vote on whether a cached snippet was useful
|
|
192
|
-
await client.voteCodeSnip({
|
|
193
|
-
task: "Fetch GitHub trending repos",
|
|
194
|
-
codeBlockId: "abc123",
|
|
195
|
-
codeBlockName: "github_fetcher",
|
|
196
|
-
codeBlockDescription: "Fetches trending repos from GitHub",
|
|
197
|
-
succeeded: true,
|
|
198
|
-
});
|
|
199
|
-
```
|
|
200
|
-
|
|
201
361
|
## License
|
|
202
362
|
|
|
203
363
|
MIT
|