Skip to content

Commit 47a1877

Browse files
Fix tests and formatting for new API
- Update tests to use new Agent, Workspace, and Conversation constructors - Test both new API and backwards compatibility exports - Fix code formatting with prettier - All CI steps now passing: build, lint, test, format:check
1 parent 704a0eb commit 47a1877

File tree

9 files changed

+88
-52
lines changed

9 files changed

+88
-52
lines changed

examples/basic-usage.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ async function main() {
1818
const workspace = new Workspace({
1919
host: 'http://localhost:3000',
2020
workingDir: '/tmp',
21-
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key'
21+
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
2222
});
2323

2424
// Create a new conversation
@@ -31,7 +31,7 @@ async function main() {
3131

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

3737
console.log(`Conversation created with ID: ${conversation.id}`);
@@ -96,11 +96,11 @@ async function loadExistingConversation() {
9696
const workspace = new Workspace({
9797
host: 'http://localhost:3000',
9898
workingDir: '/tmp',
99-
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key'
99+
apiKey: process.env.SESSION_API_KEY || 'your-session-api-key',
100100
});
101101

102102
const conversation = new Conversation(agent, workspace, {
103-
conversationId: 'existing-conversation-id'
103+
conversationId: 'existing-conversation-id',
104104
});
105105

106106
// Connect to the existing conversation

src/__tests__/index.test.ts

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,90 @@
1-
import { RemoteConversation, RemoteWorkspace } from '../index';
1+
import { Conversation, Agent, Workspace, RemoteConversation, RemoteWorkspace } from '../index';
22

33
describe('OpenHands Agent Server TypeScript Client', () => {
44
describe('Exports', () => {
5-
it('should export RemoteConversation', () => {
5+
it('should export Conversation', () => {
6+
expect(Conversation).toBeDefined();
7+
expect(typeof Conversation).toBe('function');
8+
});
9+
10+
it('should export Agent', () => {
11+
expect(Agent).toBeDefined();
12+
expect(typeof Agent).toBe('function');
13+
});
14+
15+
it('should export Workspace', () => {
16+
expect(Workspace).toBeDefined();
17+
expect(typeof Workspace).toBe('function');
18+
});
19+
20+
it('should export RemoteConversation for backwards compatibility', () => {
621
expect(RemoteConversation).toBeDefined();
722
expect(typeof RemoteConversation).toBe('function');
823
});
924

10-
it('should export RemoteWorkspace', () => {
25+
it('should export RemoteWorkspace for backwards compatibility', () => {
1126
expect(RemoteWorkspace).toBeDefined();
1227
expect(typeof RemoteWorkspace).toBe('function');
1328
});
1429
});
1530

16-
describe('RemoteConversation', () => {
17-
it('should create instance with config', () => {
18-
const config = {
31+
describe('New API - Conversation', () => {
32+
it('should create instance with agent and workspace', () => {
33+
const agent = new Agent({
34+
llm: {
35+
model: 'gpt-4',
36+
api_key: 'test-key',
37+
},
38+
});
39+
40+
const workspace = new Workspace({
1941
host: 'http://localhost:8000',
42+
workingDir: '/tmp',
2043
apiKey: 'test-key',
21-
};
44+
});
2245

23-
const conversation = new RemoteConversation(config);
46+
const conversation = new Conversation(agent, workspace);
2447
expect(conversation).toBeInstanceOf(RemoteConversation);
48+
expect(conversation.workspace).toBe(workspace);
2549
});
50+
});
2651

27-
it('should throw error when accessing workspace before initialization', () => {
28-
const config = {
29-
host: 'http://localhost:8000',
30-
apiKey: 'test-key',
31-
};
52+
describe('Agent', () => {
53+
it('should create instance with LLM config', () => {
54+
const agent = new Agent({
55+
llm: {
56+
model: 'gpt-4',
57+
api_key: 'test-key',
58+
},
59+
});
60+
61+
expect(agent).toBeInstanceOf(Agent);
62+
expect(agent.kind).toBe('Agent');
63+
expect(agent.llm.model).toBe('gpt-4');
64+
expect(agent.llm.api_key).toBe('test-key');
65+
});
66+
67+
it('should allow custom kind', () => {
68+
const agent = new Agent({
69+
kind: 'CustomAgent',
70+
llm: {
71+
model: 'gpt-4',
72+
api_key: 'test-key',
73+
},
74+
});
3275

33-
const conversation = new RemoteConversation(config);
34-
expect(() => conversation.workspace).toThrow(
35-
'Workspace not initialized. Create or load a conversation first.'
36-
);
76+
expect(agent.kind).toBe('CustomAgent');
3777
});
3878
});
3979

40-
describe('RemoteWorkspace', () => {
80+
describe('Workspace', () => {
4181
it('should create instance with options', () => {
42-
const options = {
82+
const workspace = new Workspace({
4383
host: 'http://localhost:8000',
4484
workingDir: '/tmp',
4585
apiKey: 'test-key',
46-
};
86+
});
4787

48-
const workspace = new RemoteWorkspace(options);
4988
expect(workspace).toBeInstanceOf(RemoteWorkspace);
5089
expect(workspace.host).toBe('http://localhost:8000');
5190
expect(workspace.workingDir).toBe('/tmp');

src/agent/agent.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface AgentOptions {
1515
/**
1616
* Agent class that implements AgentBase interface.
1717
* Provides a constructor-based API for creating agents.
18-
*
18+
*
1919
* Usage:
2020
* const agent = new Agent({
2121
* llm: {
@@ -34,12 +34,12 @@ export class Agent implements AgentBase {
3434
this.kind = options.kind || 'Agent';
3535
this.llm = options.llm;
3636
this.name = options.name;
37-
37+
3838
// Copy any additional properties
39-
Object.keys(options).forEach(key => {
39+
Object.keys(options).forEach((key) => {
4040
if (key !== 'kind' && key !== 'llm' && key !== 'name') {
4141
this[key] = options[key];
4242
}
4343
});
4444
}
45-
}
45+
}

src/agent/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { Agent, AgentOptions } from './agent';
1+
export { Agent, AgentOptions } from './agent';

src/conversation/conversation-manager.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ export class ConversationManager {
112112
/**
113113
* Load an existing conversation
114114
*/
115-
async loadConversation(conversationId: ConversationID, workingDir: string = '/tmp'): Promise<RemoteConversation> {
115+
async loadConversation(
116+
conversationId: ConversationID,
117+
workingDir: string = '/tmp'
118+
): Promise<RemoteConversation> {
116119
// Get conversation info to extract the agent
117120
const conversationInfo = await this.getConversation(conversationId);
118121

src/conversation/conversation.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,17 @@ import { RemoteConversation, RemoteConversationOptions } from './remote-conversa
1010
/**
1111
* Conversation class that extends RemoteConversation.
1212
* Provides a cleaner API that matches the Python SDK naming.
13-
*
13+
*
1414
* Usage:
1515
* const conversation = new Conversation(agent, workspace);
1616
* await conversation.start();
17-
*
17+
*
1818
* For existing conversations:
1919
* const conversation = new Conversation(agent, workspace, { conversationId: 'existing-id' });
2020
* await conversation.start();
2121
*/
2222
export class Conversation extends RemoteConversation {
23-
constructor(
24-
agent: AgentBase,
25-
workspace: RemoteWorkspace,
26-
options?: RemoteConversationOptions
27-
) {
23+
constructor(agent: AgentBase, workspace: RemoteWorkspace, options?: RemoteConversationOptions) {
2824
super(agent, workspace, options);
2925
}
30-
}
26+
}

src/conversation/remote-conversation.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,18 @@ export class RemoteConversation {
7070
get state(): RemoteState {
7171
if (!this._state) {
7272
if (!this._conversationId) {
73-
throw new Error('Conversation not initialized. Call start() to initialize the conversation.');
73+
throw new Error(
74+
'Conversation not initialized. Call start() to initialize the conversation.'
75+
);
7476
}
7577
this._state = new RemoteState(this.client, this._conversationId);
7678
}
7779
return this._state;
7880
}
7981

80-
async start(options: { initialMessage?: string; maxIterations?: number; stuckDetection?: boolean } = {}): Promise<void> {
82+
async start(
83+
options: { initialMessage?: string; maxIterations?: number; stuckDetection?: boolean } = {}
84+
): Promise<void> {
8185
if (this._conversationId) {
8286
// Existing conversation - verify it exists
8387
await this.client.get<ConversationInfo>(`/api/conversations/${this._conversationId}`);
@@ -211,13 +215,9 @@ export class RemoteConversation {
211215
}
212216
}
213217

214-
215-
216218
async close(): Promise<void> {
217219
await this.stopWebSocketClient();
218220
this.client.close();
219221
this.workspace.close();
220222
}
221223
}
222-
223-

src/conversation/remote-state.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,16 @@ export class RemoteState {
4444
}
4545

4646
// Fallback to REST API if no cached state
47-
const response = await this.client.get<any>(
48-
`/api/conversations/${this.conversationId}`
49-
);
50-
47+
const response = await this.client.get<any>(`/api/conversations/${this.conversationId}`);
48+
5149
// Handle the case where the API returns a full_state wrapper
5250
let conversationInfo: ConversationInfo;
5351
if (response.data.full_state) {
5452
conversationInfo = response.data.full_state as ConversationInfo;
5553
} else {
5654
conversationInfo = response.data as ConversationInfo;
5755
}
58-
56+
5957
this.cachedState = conversationInfo;
6058
return conversationInfo;
6159
});

src/workspace/workspace.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import { RemoteWorkspace, RemoteWorkspaceOptions } from './remote-workspace';
88
/**
99
* Workspace class that extends RemoteWorkspace.
1010
* Provides a cleaner API that matches the Python SDK naming.
11-
*
11+
*
1212
* Usage:
1313
* const workspace = new Workspace({ host: 'http://localhost:8000', apiKey: 'key' });
1414
*/
1515
export class Workspace extends RemoteWorkspace {
1616
constructor(options: RemoteWorkspaceOptions) {
1717
super(options);
1818
}
19-
}
19+
}

0 commit comments

Comments
 (0)