Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 39 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,32 @@ npm install @openhands/agent-server-typescript-client
### Creating a Conversation

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

const agent: AgentBase = {
name: 'CodeActAgent',
const agent = new Agent({
llm: {
model: 'gpt-4',
api_key: 'your-openai-api-key'
}
};

const conversation = await RemoteConversation.create(
'http://localhost:3000', // Agent server URL
agent,
{
apiKey: 'your-session-api-key',
initialMessage: 'Hello, can you help me write some code?',
callback: (event) => {
console.log('Received event:', event);
}
});

// Create a remote workspace
const workspace = new Workspace({
host: 'http://localhost:3000',
workingDir: '/tmp',
apiKey: 'your-session-api-key'
});

const conversation = new Conversation(agent, workspace, {
callback: (event) => {
console.log('Received event:', event);
}
);
});

// Start the conversation with an initial message
await conversation.start({
initialMessage: 'Hello, can you help me write some code?'
});

// Start WebSocket for real-time events
await conversation.startWebSocketClient();
Expand All @@ -54,13 +59,19 @@ await conversation.run();
### Loading an Existing Conversation

```typescript
const conversation = await RemoteConversation.load(
'http://localhost:3000',
'conversation-id-here',
{
apiKey: 'your-session-api-key'
}
);
// Create a remote workspace for the existing conversation
const workspace = new Workspace({
host: 'http://localhost:3000',
workingDir: '/tmp',
apiKey: 'your-session-api-key'
});

const conversation = new Conversation(agent, workspace, {
conversationId: 'conversation-id-here'
});

// Connect to the existing conversation
await conversation.start();
```

### Using the Workspace
Expand Down Expand Up @@ -120,17 +131,18 @@ await conversation.updateSecrets({

## API Reference

### RemoteConversation
### Conversation

The main class for managing conversations with OpenHands agents.
Factory function that creates conversations with OpenHands agents.

#### Static Methods
#### Constructor

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

#### Instance Methods

- `start(options?)` - Start the conversation (creates new or connects to existing)

- `sendMessage(message)` - Send a message to the agent
- `run()` - Start agent execution
- `pause()` - Pause agent execution
Expand Down
64 changes: 42 additions & 22 deletions example/src/components/ConversationManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import React, { useState, useEffect } from 'react';
import {
ConversationManager as SDKConversationManager,
ConversationInfo,
Conversation,
RemoteConversation,
AgentBase,
Agent,
Workspace,
Event
} from '@openhands/agent-server-typescript-client';
import { useSettings } from '../contexts/SettingsContext';
Expand Down Expand Up @@ -118,7 +120,7 @@ export const ConversationManager: React.FC = () => {
useEffect(() => {
return () => {
if (selectedConversation?.remoteConversation) {
selectedConversation.remoteConversation.stopWebSocketClient().catch(err => {
selectedConversation.remoteConversation.stopWebSocketClient().catch((err: any) => {
console.warn('Failed to stop WebSocket client on unmount:', err);
});
}
Expand Down Expand Up @@ -190,23 +192,24 @@ export const ConversationManager: React.FC = () => {
setError(null);
try {
// Create a simple agent configuration
const agent: AgentBase = {
kind: 'Agent',
const agent = new Agent({
llm: {
model: settings.modelName,
api_key: settings.apiKey || ''
}
};
});

// Create a remote workspace
const workspace = new Workspace({
host: manager.host,
workingDir: '/tmp',
apiKey: manager.apiKey
});

const conversation = await RemoteConversation.create(
manager.host,
agent,
{
apiKey: manager.apiKey,
initialMessage: 'Hello! I\'m ready to help you with your tasks.',
maxIterations: 50,
callback: (event: Event) => {
console.log('Received WebSocket event for new conversation:', event);
const conversation = new Conversation(agent, workspace, {
maxIterations: 50,
callback: (event: Event) => {
console.log('Received WebSocket event for new conversation:', event);

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

console.log('Created conversation:', conversation);

// Start the conversation with initial message
await conversation.start({
initialMessage: 'Hello! I\'m ready to help you with your tasks.'
});

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

// Load conversation details
try {
// Get the conversation info to extract the agent
const conversationInfo = conversations.find(c => c.id === conversationId);
if (!conversationInfo) {
throw new Error('Conversation not found');
}

// Create a callback to handle real-time events
const eventCallback = (event: Event) => {
console.log('Received WebSocket event:', event);
Expand Down Expand Up @@ -320,15 +334,21 @@ export const ConversationManager: React.FC = () => {
}
};

// Create a remote workspace for the existing conversation
const workspace = new Workspace({
host: manager.host,
workingDir: '/tmp',
apiKey: manager.apiKey
});

// Load conversation with callback
const remoteConversation = await RemoteConversation.load(
manager.host,
conversationId,
{
apiKey: manager.apiKey,
callback: eventCallback,
}
);
const remoteConversation = new Conversation(conversationInfo.agent, workspace, {
conversationId: conversationId,
callback: eventCallback,
});

// Connect to the existing conversation
await remoteConversation.start();
console.log('Loaded remote conversation:', remoteConversation);

// Start WebSocket client for real-time updates
Expand Down
23 changes: 12 additions & 11 deletions example/src/utils/serverStatus.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Settings } from '../components/SettingsModal';
import { HttpClient, RemoteConversation } from '@openhands/agent-server-typescript-client';
import { HttpClient, RemoteConversation, RemoteWorkspace } from '@openhands/agent-server-typescript-client';

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

// Create a workspace for the test conversation
const workspace = new RemoteWorkspace({
host: settings.agentServerUrl,
workingDir: '/tmp/test-workspace',
apiKey: settings.agentServerApiKey,
});

// Create a test conversation using the SDK
const conversation = await RemoteConversation.create(
settings.agentServerUrl,
const conversation = new RemoteConversation(
{
kind: 'Agent',
llm: {
model: settings.modelName,
api_key: settings.apiKey,
}
},
{
apiKey: settings.agentServerApiKey,
workspace: {
type: 'local',
path: '/tmp/test-workspace',
working_dir: '/tmp/test-workspace'
}
}
workspace
);

await conversation.start();

try {
// Send a simple test message to validate LLM configuration
await conversation.sendMessage({
Expand Down
62 changes: 40 additions & 22 deletions examples/basic-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,37 @@
* Basic usage example for the OpenHands Agent Server TypeScript Client
*/

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

async function main() {
// Define the agent configuration
const agent: AgentBase = {
name: 'CodeActAgent',
const agent = new Agent({
llm: {
model: 'gpt-4',
api_key: process.env.OPENAI_API_KEY || 'your-openai-api-key',
},
};
});

try {
// Create a remote workspace
const workspace = new Workspace({
host: 'http://localhost:3000',
workingDir: '/tmp',
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
});

// Create a new conversation
console.log('Creating conversation...');
const conversation = await RemoteConversation.create(
'http://localhost:3000', // Replace with your agent server URL
agent,
{
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
initialMessage: 'Hello! Can you help me write a simple Python script?',
callback: (event) => {
console.log(`Event received: ${event.kind} at ${event.timestamp}`);
},
}
);
const conversation = new Conversation(agent, workspace, {
callback: (event) => {
console.log(`Event received: ${event.kind} at ${event.timestamp}`);
},
});

// Start the conversation with an initial message
await conversation.start({
initialMessage: 'Hello! Can you help me write a simple Python script?',
});

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

Expand Down Expand Up @@ -79,14 +84,27 @@ async function main() {

// Example of loading an existing conversation
async function loadExistingConversation() {
const agent = new Agent({
llm: {
model: 'gpt-4',
api_key: process.env.OPENAI_API_KEY || 'your-openai-api-key',
},
});

try {
const conversation = await RemoteConversation.load(
'http://localhost:3000',
'existing-conversation-id',
{
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
}
);
// Create a remote workspace for the existing conversation
const workspace = new Workspace({
host: 'http://localhost:3000',
workingDir: '/tmp',
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
});

const conversation = new Conversation(agent, workspace, {
conversationId: 'existing-conversation-id',
});

// Connect to the existing conversation
await conversation.start();

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

Expand Down
Loading
Loading