
Security News
The Code You Didn't Write Is Still Yours to Defend
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.
@openhands/typescript-client
Advanced tools
⚠️ ALPHA SOFTWARE WARNING ⚠️
This TypeScript SDK is currently in alpha and is not stable. The API may change significantly between versions without notice. This software is intended for early testing and development purposes only.
- Breaking changes may occur in any release
- Features may be incomplete or contain bugs
- Documentation may be outdated or incomplete
- Not recommended for production use
Please use with caution and expect frequent updates.
A TypeScript client library for the OpenHands Agent Server API. Mirrors the structure and functionality of the Python OpenHands Software Agent SDK, but only supports remote conversations.
This client is fully browser-compatible and works without Node.js dependencies. File operations use browser-native APIs like Blob, File, and FormData instead of file system operations. Perfect for web applications, React apps, and other browser-based projects.
This package is published to GitHub Packages. You can install it either from GitHub Packages or directly from this repository.
Add this to your .npmrc file:
@openhands:registry=https://npm.pkg.github.com
Then install normally:
npm install @openhands/typescript-client
npm install @openhands/typescript-client --registry=https://npm.pkg.github.com
npm install github:OpenHands/typescript-client
This git-based install runs the package prepare script during installation so the published dist/ entrypoints and subpath exports are built automatically.
You'll need an AgentServer running somewhere for the client to connect to. You can run one in docker:
docker run -p 8000:8000 -p 8001:8001 \
-e OH_ENABLE_VNC=false \
-e SESSION_API_KEY="$SESSION_API_KEY" \
-e OH_ALLOW_CORS_ORIGINS='["*"]' \
ghcr.io/openhands/agent-server:71b070d-python
import { Conversation, Agent, Workspace } from '@openhands/typescript-client';
const agent = new Agent({
llm: {
model: 'gpt-4',
api_key: 'your-openai-api-key',
},
});
// 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();
// Send a message and run the agent
await conversation.sendMessage('Create a simple Python script that prints "Hello World"');
await conversation.run();
// 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();
// Execute commands
const result = await conversation.workspace.executeCommand('ls -la');
console.log('Command output:', result.stdout);
console.log('Exit code:', result.exit_code);
// Access lower-level bash APIs from the workspace
const bashCommand = await conversation.workspace.bash.startCommand('ls -la');
const bashEvents = await conversation.workspace.bash.searchEvents({
command_id__eq: bashCommand.id,
limit: 20,
});
// Upload a file
const uploadResult = await conversation.workspace.fileUpload(
'./local-file.txt',
'/remote/path/file.txt'
);
// Download a file
const downloadResult = await conversation.workspace.fileDownload(
'/remote/path/file.txt',
'./downloaded-file.txt'
);
import { ConversationManager } from '@openhands/typescript-client';
const manager = new ConversationManager({
host: 'http://localhost:3000',
apiKey: 'your-session-api-key',
});
const serverInfo = await manager.server.getServerInfo();
const providers = await manager.llm.getProviders();
const tools = await manager.tools.listTools();
const acpCount = await manager.acp.countConversations();
If you need the lower-level endpoint-specific clients directly, import them from the secondary entrypoint:
import { ServerClient, BashClient } from '@openhands/typescript-client/clients';
// Access the events list
const events = await conversation.state.events.getEvents();
console.log(`Total events: ${events.length}`);
// Iterate through events
for await (const event of conversation.state.events) {
console.log(`Event: ${event.kind} at ${event.timestamp}`);
}
// Get conversation status
const status = await conversation.state.getAgentStatus();
console.log('Agent status:', status);
// Get conversation stats
const stats = await conversation.conversationStats();
console.log('Total events:', stats.total_events);
// Set confirmation policy
await conversation.setConfirmationPolicy({ type: 'always' });
// Update secrets
await conversation.updateSecrets({
API_KEY: 'secret-value',
DATABASE_URL: () => process.env.DATABASE_URL || 'default-url',
});
Factory function that creates conversations with OpenHands agents.
new Conversation(agent, workspace, options?) - Create a new conversation instancestart(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
setConfirmationPolicy(policy) - Set confirmation policy
sendConfirmationResponse(accept, reason?) - Respond to confirmation requests
generateTitle(maxLength?, llm?) - Generate a title for the conversation
updateSecrets(secrets) - Update conversation secrets
startWebSocketClient() - Start real-time event streaming
stopWebSocketClient() - Stop real-time event streaming
conversationStats() - Get conversation statistics
close() - Clean up resources
id - Conversation IDstate - RemoteState instance for accessing conversation stateworkspace - RemoteWorkspace instance for command execution and file operationsHandles remote command execution and file operations.
executeCommand(command, cwd?, timeout?) - Execute a bash commandfileUpload(sourcePath, destinationPath) - Upload a filefileDownload(sourcePath, destinationPath) - Download a filegitChanges(path) - Get git changes for a pathgitDiff(path) - Get git diff for a pathclose() - Clean up resourcesManages conversation state and provides access to events.
id - Conversation IDevents - RemoteEventsList instancegetAgentStatus() - Get current agent execution statusgetConfirmationPolicy() - Get current confirmation policygetActivatedKnowledgeSkills() - Get activated knowledge skillsgetAgent() - Get agent configurationgetWorkspace() - Get workspace configurationgetPersistenceDir() - Get persistence directorymodelDump() - Get state as plain objectmodelDumpJson() - Get state as JSON stringManages conversation events with caching and synchronization.
addEvent(event) - Add an event to the cachelength() - Get number of cached eventsgetEvent(index) - Get event by indexgetEvents(start?, end?) - Get events slicecreateDefaultCallback() - Create a default event callbackHandles real-time event streaming via WebSocket.
start() - Start WebSocket connectionstop() - Stop WebSocket connectionThe library includes comprehensive TypeScript type definitions:
ConversationID - Conversation identifier typeEvent - Base event interfaceMessage - Message interface with contentAgentBase - Agent configuration interfaceCommandResult - Command execution resultFileOperationResult - File operation resultConversationStats - Conversation statisticsAgentExecutionStatus - Agent status enumThe client includes proper error handling with custom error types:
import { HttpError } from '@openhands/typescript-client';
try {
await conversation.sendMessage('Hello');
} catch (error) {
if (error instanceof HttpError) {
console.error(`HTTP Error ${error.status}: ${error.statusText}`);
console.error('Response:', error.response);
} else {
console.error('Unexpected error:', error);
}
}
npm run build
npm run dev
npm run lint
npm run format
Run unit tests (no external dependencies required):
npm test
Integration tests require a running agent-server in Docker with a mounted workspace. These tests verify the full functionality against a real server.
Create a workspace directory:
mkdir -p /tmp/agent-workspace
chmod 777 /tmp/agent-workspace
Start the agent-server container (software-agent-sdk v1.24.0):
docker run -d \
--name agent-server \
-p 8010:8000 \
-v /tmp/agent-workspace:/workspace \
ghcr.io/openhands/agent-server:1.24.0-python
Wait for the server to be ready:
# Check server health
curl http://localhost:8010/health
Run integration tests:
export LLM_API_KEY="your-api-key"
export LLM_MODEL="anthropic/claude-sonnet-4-5-20250929"
npm run test:integration
Cleanup:
docker stop agent-server && docker rm agent-server
| Variable | Required | Default | Description |
|---|---|---|---|
LLM_API_KEY | Yes | - | API key for the LLM provider |
LLM_MODEL | Yes | - | LLM model name (e.g., anthropic/claude-sonnet-4-5-20250929) |
LLM_BASE_URL | No | - | Custom base URL for LLM API |
AGENT_SERVER_URL | No | http://localhost:8010 | URL of the agent server |
HOST_WORKSPACE_DIR | No | /tmp/agent-workspace | Path to workspace on host |
AGENT_WORKSPACE_DIR | No | /workspace | Path to workspace inside container |
TEST_TIMEOUT | No | 120000 | Test timeout in milliseconds |
The integration tests cover:
Integration tests run automatically in GitHub Actions when:
main or develop branchesThe workflow requires the following secrets:
LLM_API_KEY: API key for the LLM providerLLM_MODEL (optional): Override the default modelnpm run test:all
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
FAQs
TypeScript client for OpenHands Agent Server
The npm package @openhands/typescript-client receives a total of 2,656 weekly downloads. As such, @openhands/typescript-client popularity was classified as popular.
We found that @openhands/typescript-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
AI agents are pulling packages into environments no scanner is watching, creating exposure before security teams can see it.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.