Skip to content

Commit 6ec8f27

Browse files
authored
Merge pull request #17 from OpenHands/feat/update-sdk-api-aliases
feat: Update SDK API to use Agent and Conversation aliases with explicit workspace creation
2 parents bc6de9d + 47a1877 commit 6ec8f27

File tree

14 files changed

+397
-227
lines changed

14 files changed

+397
-227
lines changed

README.md

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,32 @@ A TypeScript client library for the OpenHands Agent Server API that mirrors the
1515
### Creating a Conversation
1616

1717
```typescript
18-
import { RemoteConversation, AgentBase } from '@openhands/agent-server-typescript-client';
18+
import { Conversation, Agent, Workspace } from '@openhands/agent-server-typescript-client';
1919

20-
const agent: AgentBase = {
21-
name: 'CodeActAgent',
20+
const agent = new Agent({
2221
llm: {
2322
model: 'gpt-4',
2423
api_key: 'your-openai-api-key'
2524
}
26-
};
27-
28-
const conversation = await RemoteConversation.create(
29-
'http://localhost:3000', // Agent server URL
30-
agent,
31-
{
32-
apiKey: 'your-session-api-key',
33-
initialMessage: 'Hello, can you help me write some code?',
34-
callback: (event) => {
35-
console.log('Received event:', event);
36-
}
25+
});
26+
27+
// Create a remote workspace
28+
const workspace = new Workspace({
29+
host: 'http://localhost:3000',
30+
workingDir: '/tmp',
31+
apiKey: 'your-session-api-key'
32+
});
33+
34+
const conversation = new Conversation(agent, workspace, {
35+
callback: (event) => {
36+
console.log('Received event:', event);
3737
}
38-
);
38+
});
39+
40+
// Start the conversation with an initial message
41+
await conversation.start({
42+
initialMessage: 'Hello, can you help me write some code?'
43+
});
3944

4045
// Start WebSocket for real-time events
4146
await conversation.startWebSocketClient();
@@ -48,13 +53,19 @@ await conversation.run();
4853
### Loading an Existing Conversation
4954

5055
```typescript
51-
const conversation = await RemoteConversation.load(
52-
'http://localhost:3000',
53-
'conversation-id-here',
54-
{
55-
apiKey: 'your-session-api-key'
56-
}
57-
);
56+
// Create a remote workspace for the existing conversation
57+
const workspace = new Workspace({
58+
host: 'http://localhost:3000',
59+
workingDir: '/tmp',
60+
apiKey: 'your-session-api-key'
61+
});
62+
63+
const conversation = new Conversation(agent, workspace, {
64+
conversationId: 'conversation-id-here'
65+
});
66+
67+
// Connect to the existing conversation
68+
await conversation.start();
5869
```
5970

6071
### Using the Workspace
@@ -114,17 +125,18 @@ await conversation.updateSecrets({
114125

115126
## API Reference
116127

117-
### RemoteConversation
128+
### Conversation
118129

119-
The main class for managing conversations with OpenHands agents.
130+
Factory function that creates conversations with OpenHands agents.
120131

121-
#### Static Methods
132+
#### Constructor
122133

123-
- `RemoteConversation.create(host, agent, options)` - Create a new conversation
124-
- `RemoteConversation.load(host, conversationId, options)` - Load an existing conversation
134+
- `new Conversation(agent, workspace, options?)` - Create a new conversation instance
125135

126136
#### Instance Methods
127137

138+
- `start(options?)` - Start the conversation (creates new or connects to existing)
139+
128140
- `sendMessage(message)` - Send a message to the agent
129141
- `run()` - Start agent execution
130142
- `pause()` - Pause agent execution

example/src/components/ConversationManager.tsx

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import React, { useState, useEffect } from 'react';
22
import {
33
ConversationManager as SDKConversationManager,
44
ConversationInfo,
5+
Conversation,
56
RemoteConversation,
6-
AgentBase,
7+
Agent,
8+
Workspace,
79
Event
810
} from '@openhands/agent-server-typescript-client';
911
import { useSettings } from '../contexts/SettingsContext';
@@ -118,7 +120,7 @@ export const ConversationManager: React.FC = () => {
118120
useEffect(() => {
119121
return () => {
120122
if (selectedConversation?.remoteConversation) {
121-
selectedConversation.remoteConversation.stopWebSocketClient().catch(err => {
123+
selectedConversation.remoteConversation.stopWebSocketClient().catch((err: any) => {
122124
console.warn('Failed to stop WebSocket client on unmount:', err);
123125
});
124126
}
@@ -190,23 +192,24 @@ export const ConversationManager: React.FC = () => {
190192
setError(null);
191193
try {
192194
// Create a simple agent configuration
193-
const agent: AgentBase = {
194-
kind: 'Agent',
195+
const agent = new Agent({
195196
llm: {
196197
model: settings.modelName,
197198
api_key: settings.apiKey || ''
198199
}
199-
};
200+
});
201+
202+
// Create a remote workspace
203+
const workspace = new Workspace({
204+
host: manager.host,
205+
workingDir: '/tmp',
206+
apiKey: manager.apiKey
207+
});
200208

201-
const conversation = await RemoteConversation.create(
202-
manager.host,
203-
agent,
204-
{
205-
apiKey: manager.apiKey,
206-
initialMessage: 'Hello! I\'m ready to help you with your tasks.',
207-
maxIterations: 50,
208-
callback: (event: Event) => {
209-
console.log('Received WebSocket event for new conversation:', event);
209+
const conversation = new Conversation(agent, workspace, {
210+
maxIterations: 50,
211+
callback: (event: Event) => {
212+
console.log('Received WebSocket event for new conversation:', event);
210213

211214
// Update the conversation's events in real-time
212215
setConversations(prev => prev.map(conv => {
@@ -221,6 +224,11 @@ export const ConversationManager: React.FC = () => {
221224
);
222225

223226
console.log('Created conversation:', conversation);
227+
228+
// Start the conversation with initial message
229+
await conversation.start({
230+
initialMessage: 'Hello! I\'m ready to help you with your tasks.'
231+
});
224232

225233
// Start WebSocket client for real-time updates
226234
try {
@@ -289,6 +297,12 @@ export const ConversationManager: React.FC = () => {
289297

290298
// Load conversation details
291299
try {
300+
// Get the conversation info to extract the agent
301+
const conversationInfo = conversations.find(c => c.id === conversationId);
302+
if (!conversationInfo) {
303+
throw new Error('Conversation not found');
304+
}
305+
292306
// Create a callback to handle real-time events
293307
const eventCallback = (event: Event) => {
294308
console.log('Received WebSocket event:', event);
@@ -320,15 +334,21 @@ export const ConversationManager: React.FC = () => {
320334
}
321335
};
322336

337+
// Create a remote workspace for the existing conversation
338+
const workspace = new Workspace({
339+
host: manager.host,
340+
workingDir: '/tmp',
341+
apiKey: manager.apiKey
342+
});
343+
323344
// Load conversation with callback
324-
const remoteConversation = await RemoteConversation.load(
325-
manager.host,
326-
conversationId,
327-
{
328-
apiKey: manager.apiKey,
329-
callback: eventCallback,
330-
}
331-
);
345+
const remoteConversation = new Conversation(conversationInfo.agent, workspace, {
346+
conversationId: conversationId,
347+
callback: eventCallback,
348+
});
349+
350+
// Connect to the existing conversation
351+
await remoteConversation.start();
332352
console.log('Loaded remote conversation:', remoteConversation);
333353

334354
// Start WebSocket client for real-time updates

example/src/utils/serverStatus.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Settings } from '../components/SettingsModal';
2-
import { HttpClient, RemoteConversation } from '@openhands/agent-server-typescript-client';
2+
import { HttpClient, RemoteConversation, RemoteWorkspace } from '@openhands/agent-server-typescript-client';
33

44
export interface ServerStatus {
55
isConnected: boolean;
@@ -51,26 +51,27 @@ export const testLLMConfiguration = async (settings: Settings): Promise<{ succes
5151
return { success: false, error: `Server not reachable: ${healthCheck.error}` };
5252
}
5353

54+
// Create a workspace for the test conversation
55+
const workspace = new RemoteWorkspace({
56+
host: settings.agentServerUrl,
57+
workingDir: '/tmp/test-workspace',
58+
apiKey: settings.agentServerApiKey,
59+
});
60+
5461
// Create a test conversation using the SDK
55-
const conversation = await RemoteConversation.create(
56-
settings.agentServerUrl,
62+
const conversation = new RemoteConversation(
5763
{
5864
kind: 'Agent',
5965
llm: {
6066
model: settings.modelName,
6167
api_key: settings.apiKey,
6268
}
6369
},
64-
{
65-
apiKey: settings.agentServerApiKey,
66-
workspace: {
67-
type: 'local',
68-
path: '/tmp/test-workspace',
69-
working_dir: '/tmp/test-workspace'
70-
}
71-
}
70+
workspace
7271
);
7372

73+
await conversation.start();
74+
7475
try {
7576
// Send a simple test message to validate LLM configuration
7677
await conversation.sendMessage({

examples/basic-usage.ts

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,37 @@
22
* Basic usage example for the OpenHands Agent Server TypeScript Client
33
*/
44

5-
import { RemoteConversation, AgentBase, AgentExecutionStatus } from '../src/index.js';
5+
import { Conversation, Agent, Workspace, AgentExecutionStatus } from '../src/index.js';
66

77
async function main() {
88
// Define the agent configuration
9-
const agent: AgentBase = {
10-
name: 'CodeActAgent',
9+
const agent = new Agent({
1110
llm: {
1211
model: 'gpt-4',
1312
api_key: process.env.OPENAI_API_KEY || 'your-openai-api-key',
1413
},
15-
};
14+
});
1615

1716
try {
17+
// Create a remote workspace
18+
const workspace = new Workspace({
19+
host: 'http://localhost:3000',
20+
workingDir: '/tmp',
21+
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
22+
});
23+
1824
// Create a new conversation
1925
console.log('Creating conversation...');
20-
const conversation = await RemoteConversation.create(
21-
'http://localhost:3000', // Replace with your agent server URL
22-
agent,
23-
{
24-
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
25-
initialMessage: 'Hello! Can you help me write a simple Python script?',
26-
callback: (event) => {
27-
console.log(`Event received: ${event.kind} at ${event.timestamp}`);
28-
},
29-
}
30-
);
26+
const conversation = new Conversation(agent, workspace, {
27+
callback: (event) => {
28+
console.log(`Event received: ${event.kind} at ${event.timestamp}`);
29+
},
30+
});
31+
32+
// Start the conversation with an initial message
33+
await conversation.start({
34+
initialMessage: 'Hello! Can you help me write a simple Python script?',
35+
});
3136

3237
console.log(`Conversation created with ID: ${conversation.id}`);
3338

@@ -79,14 +84,27 @@ async function main() {
7984

8085
// Example of loading an existing conversation
8186
async function loadExistingConversation() {
87+
const agent = new Agent({
88+
llm: {
89+
model: 'gpt-4',
90+
api_key: process.env.OPENAI_API_KEY || 'your-openai-api-key',
91+
},
92+
});
93+
8294
try {
83-
const conversation = await RemoteConversation.load(
84-
'http://localhost:3000',
85-
'existing-conversation-id',
86-
{
87-
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
88-
}
89-
);
95+
// Create a remote workspace for the existing conversation
96+
const workspace = new Workspace({
97+
host: 'http://localhost:3000',
98+
workingDir: '/tmp',
99+
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
100+
});
101+
102+
const conversation = new Conversation(agent, workspace, {
103+
conversationId: 'existing-conversation-id',
104+
});
105+
106+
// Connect to the existing conversation
107+
await conversation.start();
90108

91109
console.log(`Loaded conversation: ${conversation.id}`);
92110

0 commit comments

Comments
 (0)