@castari/sdk 0.1.4 → 0.1.5
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 +84 -6
- package/dist/client.d.ts +5 -0
- package/dist/client.js +15 -2
- package/dist/server.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @castari/sdk
|
|
2
2
|
|
|
3
|
-
The SDK for building and connecting to Castari agents.
|
|
3
|
+
The SDK for building and connecting to Castari agents running in secure cloud sandboxes.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -70,7 +70,7 @@ const weatherTool = tool({
|
|
|
70
70
|
|
|
71
71
|
### `CastariClient`
|
|
72
72
|
|
|
73
|
-
A client for connecting to Castari agents.
|
|
73
|
+
A client for connecting to Castari agents running in cloud sandboxes.
|
|
74
74
|
|
|
75
75
|
```typescript
|
|
76
76
|
import { CastariClient } from '@castari/sdk/client'
|
|
@@ -85,7 +85,9 @@ const client = new CastariClient({
|
|
|
85
85
|
await client.start()
|
|
86
86
|
|
|
87
87
|
client.onMessage((msg) => {
|
|
88
|
-
|
|
88
|
+
if (msg.type === 'assistant_message') {
|
|
89
|
+
console.log('Agent:', msg.data.message)
|
|
90
|
+
}
|
|
89
91
|
})
|
|
90
92
|
|
|
91
93
|
client.send({
|
|
@@ -101,23 +103,69 @@ await client.stop()
|
|
|
101
103
|
|
|
102
104
|
| Property | Type | Description |
|
|
103
105
|
|----------|------|-------------|
|
|
104
|
-
| `snapshot` | `string` | Name of the snapshot to use |
|
|
106
|
+
| `snapshot` | `string` | Name of the deployed snapshot to use |
|
|
105
107
|
| `clientId` | `string` | Your Castari client ID |
|
|
106
108
|
| `platformApiKey` | `string` | Your Castari API key |
|
|
107
109
|
| `anthropicApiKey` | `string` | Your Anthropic API key |
|
|
108
110
|
| `volume` | `string` | (Optional) Volume name for persistent storage |
|
|
109
111
|
| `labels` | `Record<string, string>` | (Optional) Labels for sandbox reuse |
|
|
112
|
+
| `resume` | `string` | (Optional) Session ID to resume a previous conversation |
|
|
110
113
|
| `connectionUrl` | `string` | (Optional) Direct URL for local development |
|
|
111
|
-
| `platformUrl` | `string` | (Optional) Override the platform URL
|
|
114
|
+
| `platformUrl` | `string` | (Optional) Override the platform URL |
|
|
115
|
+
| `useProxy` | `boolean` | (Optional) Use platform proxy. Defaults to `true` |
|
|
116
|
+
| `debug` | `boolean` | (Optional) Enable debug logging |
|
|
112
117
|
|
|
113
118
|
#### Methods
|
|
114
119
|
|
|
115
120
|
- `start()` - Creates a sandbox and connects to the agent
|
|
116
121
|
- `stop(options?)` - Disconnects and cleans up
|
|
117
122
|
- `{ delete: false }` - Stop but preserve sandbox for reuse
|
|
123
|
+
- `{ delete: true }` (default) - Delete the sandbox
|
|
118
124
|
- `send(message)` - Send a message to the agent
|
|
119
125
|
- `onMessage(callback)` - Register a callback for incoming messages
|
|
120
126
|
|
|
127
|
+
### Message Types
|
|
128
|
+
|
|
129
|
+
#### Input Messages (client to agent)
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// Send a user message
|
|
133
|
+
client.send({
|
|
134
|
+
type: 'user_message',
|
|
135
|
+
data: { message: 'Hello!' }
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### Output Messages (agent to client)
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
client.onMessage((msg) => {
|
|
143
|
+
switch (msg.type) {
|
|
144
|
+
case 'connected':
|
|
145
|
+
// Connection established
|
|
146
|
+
break
|
|
147
|
+
case 'assistant_message':
|
|
148
|
+
// Text response from the agent
|
|
149
|
+
console.log(msg.data.message)
|
|
150
|
+
break
|
|
151
|
+
case 'tool_use':
|
|
152
|
+
// Agent is using a tool
|
|
153
|
+
console.log(`Using tool: ${msg.data.name}`)
|
|
154
|
+
break
|
|
155
|
+
case 'tool_result':
|
|
156
|
+
// Tool execution result
|
|
157
|
+
break
|
|
158
|
+
case 'done':
|
|
159
|
+
// Agent finished processing
|
|
160
|
+
break
|
|
161
|
+
case 'error':
|
|
162
|
+
// Error occurred
|
|
163
|
+
console.error(msg.data.error)
|
|
164
|
+
break
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
121
169
|
### Sandbox Reuse
|
|
122
170
|
|
|
123
171
|
Use labels to reuse sandboxes across sessions:
|
|
@@ -132,13 +180,43 @@ const client = new CastariClient({
|
|
|
132
180
|
}
|
|
133
181
|
})
|
|
134
182
|
|
|
135
|
-
// First call creates, subsequent calls reuse
|
|
183
|
+
// First call creates, subsequent calls reuse the same sandbox
|
|
136
184
|
await client.start()
|
|
137
185
|
|
|
138
186
|
// Stop but preserve for later
|
|
139
187
|
await client.stop({ delete: false })
|
|
140
188
|
```
|
|
141
189
|
|
|
190
|
+
### Session Resumption
|
|
191
|
+
|
|
192
|
+
Resume a previous conversation:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// Store the session ID from a previous session
|
|
196
|
+
const sessionId = previousSessionId
|
|
197
|
+
|
|
198
|
+
const client = new CastariClient({
|
|
199
|
+
snapshot: 'my-agent',
|
|
200
|
+
resume: sessionId
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
await client.start()
|
|
204
|
+
// Conversation continues where it left off
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Local Development
|
|
208
|
+
|
|
209
|
+
Connect directly to a local agent server:
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const client = new CastariClient({
|
|
213
|
+
connectionUrl: 'http://localhost:3000',
|
|
214
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
await client.start()
|
|
218
|
+
```
|
|
219
|
+
|
|
142
220
|
## Environment Variables
|
|
143
221
|
|
|
144
222
|
| Variable | Description |
|
package/dist/client.d.ts
CHANGED
|
@@ -34,15 +34,20 @@ export declare class CastariClient {
|
|
|
34
34
|
private ws?;
|
|
35
35
|
private options;
|
|
36
36
|
private messageHandlers;
|
|
37
|
+
private closeHandlers;
|
|
37
38
|
private sandboxId?;
|
|
38
39
|
private resolvedClientId?;
|
|
39
40
|
private resolvedPlatformApiKey?;
|
|
40
41
|
constructor(options?: ClientOptions);
|
|
42
|
+
/** Check if the WebSocket is currently connected */
|
|
43
|
+
isConnected(): boolean;
|
|
41
44
|
start(): Promise<void>;
|
|
42
45
|
private setupLocalConnection;
|
|
43
46
|
private setupPlatformConnection;
|
|
44
47
|
private handleMessage;
|
|
45
48
|
onMessage(handler: (message: WSOutputMessage) => void): () => void;
|
|
49
|
+
/** Register a callback for when the WebSocket connection closes */
|
|
50
|
+
onClose(handler: (code: number, reason: string) => void): () => void;
|
|
46
51
|
send(message: WSInputMessage): void;
|
|
47
52
|
stop(options?: {
|
|
48
53
|
delete?: boolean;
|
package/dist/client.js
CHANGED
|
@@ -5,6 +5,7 @@ export class CastariClient {
|
|
|
5
5
|
ws;
|
|
6
6
|
options;
|
|
7
7
|
messageHandlers = [];
|
|
8
|
+
closeHandlers = [];
|
|
8
9
|
sandboxId;
|
|
9
10
|
resolvedClientId;
|
|
10
11
|
resolvedPlatformApiKey;
|
|
@@ -13,6 +14,10 @@ export class CastariClient {
|
|
|
13
14
|
...options,
|
|
14
15
|
};
|
|
15
16
|
}
|
|
17
|
+
/** Check if the WebSocket is currently connected */
|
|
18
|
+
isConnected() {
|
|
19
|
+
return this.ws?.readyState === WebSocket.OPEN;
|
|
20
|
+
}
|
|
16
21
|
async start() {
|
|
17
22
|
const anthropicApiKey = this.options.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
|
|
18
23
|
if (!anthropicApiKey) {
|
|
@@ -110,9 +115,10 @@ export class CastariClient {
|
|
|
110
115
|
console.error('WebSocket error:', error);
|
|
111
116
|
reject(error);
|
|
112
117
|
};
|
|
113
|
-
this.ws.onclose = () => {
|
|
118
|
+
this.ws.onclose = (event) => {
|
|
114
119
|
if (this.options.debug)
|
|
115
|
-
console.log(
|
|
120
|
+
console.log(`👋 Disconnected (code=${event.code})`);
|
|
121
|
+
this.closeHandlers.forEach(handler => handler(event.code, event.reason));
|
|
116
122
|
};
|
|
117
123
|
});
|
|
118
124
|
}
|
|
@@ -200,6 +206,13 @@ export class CastariClient {
|
|
|
200
206
|
this.messageHandlers = this.messageHandlers.filter(h => h !== handler);
|
|
201
207
|
};
|
|
202
208
|
}
|
|
209
|
+
/** Register a callback for when the WebSocket connection closes */
|
|
210
|
+
onClose(handler) {
|
|
211
|
+
this.closeHandlers.push(handler);
|
|
212
|
+
return () => {
|
|
213
|
+
this.closeHandlers = this.closeHandlers.filter(h => h !== handler);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
203
216
|
send(message) {
|
|
204
217
|
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
|
205
218
|
throw new Error('WebSocket is not connected');
|
package/dist/server.js
CHANGED
|
@@ -190,6 +190,9 @@ export async function serve(options = {}) {
|
|
|
190
190
|
return new Response('Not Found', { status: 404 });
|
|
191
191
|
},
|
|
192
192
|
websocket: {
|
|
193
|
+
// Keep connection alive as long as sandbox is running
|
|
194
|
+
idleTimeout: 0,
|
|
195
|
+
sendPings: true,
|
|
193
196
|
open(ws) {
|
|
194
197
|
activeConnection = ws;
|
|
195
198
|
// Start processing messages when first connection is made
|