@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 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
- console.log('Agent:', msg)
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 (advanced) |
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('👋 Disconnected');
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@castari/sdk",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",