How to Implement a Custom Operator Class for UI-TARS SDK
To implement a custom Operator class for the UI-TARS SDK, extend the abstract Operator class and implement the screenshot() method to capture UI state and the execute() method to handle parsed model predictions.
The UI-TARS SDK, part of the bytedance/UI-TARS-desktop repository, provides a flexible framework for building GUI automation agents. The Operator abstraction serves as the critical bridge between the AI model's predictions and your specific UI environment, requiring you to implement screenshot capture and action execution logic tailored to your application.
Understanding the Operator Contract
The UI-TARS SDK defines the operator interface in packages/ui-tars/sdk/src/types.ts (lines 66-73). According to the source code, every operator must satisfy two fundamental requirements:
- Screenshot capture: The
screenshot()method must return aPromise<ScreenshotOutput>containing a base64-encoded image string, width, height, and screen scale factor. - Action execution: The
execute()method receives anExecuteParamsobject and returns aPromise<ExecuteOutput>with a status of eitherStatusEnum.RUNNINGorStatusEnum.END.
The abstract class extends BaseOperator from packages/ui-tars/sdk/src/base/index.ts (lines 40-46), which provides the type signatures while leaving the concrete implementation to subclasses.
Building a Minimal Custom Operator
Create a concrete implementation by importing the Operator class from @ui-tars/sdk and implementing the required methods:
import { Operator, ExecuteParams, ExecuteOutput, ScreenshotOutput } from '@ui-tars/sdk';
import { Jimp } from 'jimp';
class MyOperator extends Operator {
// Capture current UI state
screenshot = async (): Promise<ScreenshotOutput> => {
const img = await new Jimp({ width: 1280, height: 720, color: 0xffffffff });
const buf = await img.getBuffer('image/png');
return {
base64: buf.toString('base64'),
width: 1280,
height: 720,
scaleFactor: 1,
};
};
// Execute parsed predictions from the model
execute = async (params: ExecuteParams): Promise<ExecuteOutput> => {
console.log('Executing action:', params.parsedPrediction);
// Implement actual UI interactions (click, type, etc.) here
return { status: StatusEnum.RUNNING };
};
}
Customizing Action Spaces with the MANUAL Field
Override the default action space by defining a static MANUAL field on your class. As demonstrated in packages/ui-tars/sdk/tests/GUIAgent.test.ts (lines 29-36), the SDK embeds these definitions into the system prompt automatically.
class MySpecialOperator extends Operator {
static MANUAL = {
ACTION_SPACES: [
`CLICK(start_box='[x1, y1, x2, y2]')`,
`TYPE(text='your text')`,
`END()`,
],
};
// screenshot and execute implementations as above
}
Integrating Your Operator with GUIAgent
The GUIAgent class orchestrates the interaction between your operator and the AI model. Pass your custom operator instance via the operator field in the configuration:
import { GUIAgent } from '@ui-tars/sdk';
import { MyOperator } from './my-operator';
const agent = new GUIAgent({
model: {
baseURL: 'http://localhost:3000/v1',
apiKey: 'YOUR_KEY',
model: 'ui-tars'
},
operator: new MyOperator(),
onData: ({ data }) => console.log('Agent data:', data),
onError: ({ data, error }) => console.error('Agent error:', error),
});
await agent.run('click the Submit button');
The GUIAgent calls operator.screenshot() once per turn, feeds the screenshot to the model, receives a prediction, then invokes operator.execute() with the parsed prediction data.
Key Source Files and Architecture
| File | Purpose |
|---|---|
packages/ui-tars/sdk/src/types.ts |
Abstract Operator class definition (lines 66-73) |
packages/ui-tars/sdk/src/base/index.ts |
BaseOperator base class (lines 40-46) |
packages/ui-tars/sdk/src/GUIAgent.ts |
Core agent that orchestrates the operator |
packages/ui-tars/sdk/tests/GUIAgent.test.ts |
Test cases including custom action spaces (lines 29-36) |
packages/ui-tars/sdk/src/context/useContext.ts |
Utility to access SDK context inside execute |
Summary
- Extend the abstract
Operatorclass from@ui-tars/sdkto create your implementation. - Implement
screenshot()to return base64-encoded images with dimensions and scale factors. - Implement
execute()to handleExecuteParamsand returnExecuteOutputwith appropriate status enums. - Define a static
MANUALfield to customize available action spaces for the model. - Inject your operator instance into
GUIAgentvia the configuration object.
Frequently Asked Questions
What is the purpose of the Operator class in UI-TARS?
The Operator class serves as the bridge between the AI model and your specific UI environment. According to the SDK source code in packages/ui-tars/sdk/src/types.ts, it abstractly defines how the agent captures screenshots and executes predicted actions, allowing you to implement platform-specific logic for any GUI framework.
Do I need to implement both screenshot and execute methods?
Yes. The UI-TARS SDK requires both methods as defined in the abstract class at packages/ui-tars/sdk/src/types.ts (lines 66-73). The screenshot() method enables the model to perceive the current UI state, while execute() translates the model's predictions into actual UI interactions. Omitting either method will result in a compilation error when extending the abstract class.
Can I customize which actions the model can use?
Yes. Define a static MANUAL field containing an ACTION_SPACES array on your operator class. As shown in packages/ui-tars/sdk/tests/GUIAgent.test.ts (lines 29-36), the SDK automatically injects these action definitions into the system prompt sent to the model, restricting it to only the actions your implementation supports.
How do I access SDK context inside my operator?
Import and call useContext() from packages/ui-tars/sdk/src/context/useContext.ts within your execute method. This utility provides access to the SDK's internal context, enabling logging, configuration access, and state management during action execution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →