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
2 changes: 1 addition & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ env:
AGENT_SERVER_PORT: 8010
HOST_WORKSPACE_DIR: /tmp/agent-workspace
AGENT_WORKSPACE_DIR: /workspace
AGENT_SERVER_IMAGE: ghcr.io/openhands/agent-server:7c37803-python # software-agent-sdk v1.18.1
AGENT_SERVER_IMAGE: ghcr.io/openhands/agent-server:b1235d0-python # software-agent-sdk v1.23.0

jobs:
integration-test:
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,10 +304,10 @@ Integration tests are in `src/__tests__/integration/` and require a running agen
export LLM_API_KEY="your-api-key"
export LLM_MODEL="anthropic/claude-sonnet-4-5-20250929"

# Start agent-server in Docker (software-agent-sdk v1.18.1)
# Start agent-server in Docker (software-agent-sdk v1.23.0)
docker run -d --name agent-server -p 8010:8000 \
-v /tmp/agent-workspace:/workspace \
ghcr.io/openhands/agent-server:7c37803-python
ghcr.io/openhands/agent-server:b1235d0-python

# Run integration tests
npm run test:integration
Expand Down Expand Up @@ -336,7 +336,7 @@ Required GitHub secrets:

### CI Image Version

- The integration workflow pins `ghcr.io/openhands/agent-server:7c37803-python`, which corresponds to the `software-agent-sdk` release `v1.18.1`.
- The integration workflow pins `ghcr.io/openhands/agent-server:b1235d0-python`, which corresponds to the `software-agent-sdk` release `v1.23.0`.
- Keep the TypeScript client tests strict against that released server image rather than adding compatibility fallbacks for older prerelease builds.

## Agent Behavior Guidelines
Expand Down
12 changes: 9 additions & 3 deletions src/__tests__/api-clients.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,7 @@ describe('Auxiliary API clients', () => {
const client = new ConversationClient({ host: 'http://example.com' });
await client.sendEvent('c1', { role: 'user', content: [] }, { run: true });
await client.pauseConversation('c1');
await client.interruptConversation('c1');
await client.runConversation('c1');
await client.askAgent('c1', 'status?');
await client.respondToConfirmation('c1', { accept: true });
Expand All @@ -775,17 +776,22 @@ describe('Auxiliary API clients', () => {
})
);
expect(global.fetch).toHaveBeenNthCalledWith(
4,
3,
'http://example.com/api/conversations/c1/interrupt',
expect.objectContaining({ method: 'POST', body: JSON.stringify({}) })
);
expect(global.fetch).toHaveBeenNthCalledWith(
5,
'http://example.com/api/conversations/c1/ask_agent',
expect.objectContaining({ method: 'POST', body: JSON.stringify({ question: 'status?' }) })
);
expect(global.fetch).toHaveBeenNthCalledWith(
5,
6,
'http://example.com/api/conversations/c1/events/respond_to_confirmation',
expect.objectContaining({ method: 'POST', body: JSON.stringify({ accept: true }) })
);
expect(global.fetch).toHaveBeenNthCalledWith(
7,
8,
'http://example.com/api/conversations/c1',
expect.objectContaining({ method: 'PATCH', body: JSON.stringify({ title: 'New title' }) })
);
Expand Down
13 changes: 6 additions & 7 deletions src/__tests__/integration/deterministic-api.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('Deterministic API Integration Tests', () => {

expect(root).toBeDefined();
expect(alive.status).toBe('ok');
expect(health).toBe('OK');
expect(health.status).toBe('ok');
expect(['ready', 'initializing']).toContain(ready.status);
expect(info.version).toBeDefined();
expect(Array.isArray(providers)).toBe(true);
Expand Down Expand Up @@ -114,14 +114,13 @@ describe('Deterministic API Integration Tests', () => {
const finalResponse = await conversation.getAgentFinalResponse();
expect(typeof finalResponse).toBe('string');

const trajectoryFile = `/workspace/conversations/${conversation.id.replace(/-/g, '')}.zip`;
await workspace.executeCommand(
`mkdir -p /workspace/conversations && printf 'trajectory-data' > ${trajectoryFile}`
);
const trajectory = await conversation.downloadTrajectory();
expect(trajectory).toBeInstanceOf(Blob);
expect(await trajectory.text()).toContain('trajectory-data');
await workspace.executeCommand(`rm -f ${trajectoryFile}`);
expect(trajectory.size).toBeGreaterThan(0);
const trajectoryBytes = new Uint8Array(await trajectory.arrayBuffer());
// Verify it's a valid ZIP file (PK\x03\x04 magic bytes)
expect(trajectoryBytes[0]).toBe(0x50); // P
expect(trajectoryBytes[1]).toBe(0x4b); // K

const forkedConversation = await conversation.fork({
title: 'Forked from deterministic test',
Expand Down
8 changes: 8 additions & 0 deletions src/client/conversation-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ export class ConversationClient {
return response.data;
}

async interruptConversation(conversationId: string): Promise<Success> {
const response = await this.client.post<Success>(
`/api/conversations/${conversationId}/interrupt`,
{}
);
return response.data;
}

async runConversation(conversationId: string): Promise<Success> {
const response = await this.client.post<Success>(
`/api/conversations/${conversationId}/run`,
Expand Down
6 changes: 3 additions & 3 deletions src/client/server-client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpClient } from './http-client';
import { AliveStatus, ReadyStatus } from '../models/api';
import { AliveStatus, HealthStatus, ReadyStatus } from '../models/api';
import { ServerInfo } from '../types/base';

export interface ServerClientOptions {
Expand Down Expand Up @@ -33,8 +33,8 @@ export class ServerClient {
return response.data;
}

async getHealth(): Promise<string> {
const response = await this.client.get<string>('/health');
async getHealth(): Promise<HealthStatus> {
const response = await this.client.get<HealthStatus>('/health');
return response.data;
}

Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export type { HttpClientOptions, RequestOptions, HttpResponse } from './client/h

export type {
AliveStatus,
HealthStatus,
ReadyStatus,
ProvidersResponse,
ModelsResponse,
Expand Down
4 changes: 4 additions & 0 deletions src/models/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export interface AliveStatus {
status: string;
}

export interface HealthStatus {
status: string;
}

export interface ReadyStatus {
status: string;
message?: string;
Expand Down
Loading