Lybic Docs

gRPC & Service Deployment

gRPC Server (grpc_app)

The gRPC application exposes the GUI Agent as a long‑running service for multi-language integration, remote orchestration, metrics, and persistence. Binary entrypoint inside the container:

/app/.venv/bin/lybic-guiagent-grpc

(When installed locally you can invoke via lybic-guiagent-grpc if your environment's bin directory is on PATH.)

Proto Files

The table below briefly describes the main interfaces of the Agent gRPC API and their uses, along with typical usage examples:

MethodPurposeExample
GetAgentInfoRetrieve Agent version and capabilities information.resp = stub.GetAgentInfo(agent_pb2.GetAgentInfoRequest())
GetGlobalCommonConfigGet global general configuration.resp = stub.GetGlobalCommonConfig(agent_pb2.GetGlobalCommonConfigRequest())
SetGlobalCommonConfigSet global general configuration.resp = stub.SetGlobalCommonConfig(agent_pb2.SetGlobalCommonConfigRequest(commonConfig=...))
SetGlobalCommonLLMConfig/SetGlobalGroundingLLMConfig/SetGlobalEmbeddingLLMConfigConfigure global LLM/embedding/grounding models. Refer to Model Support & Configuration Referenceresp = stub.SetGlobalCommonLLMConfig(agent_pb2.SetGlobalCommonLLMConfigRequest(llmConfig=...))
RunAgentInstructionExecute natural language instructions synchronously and return streaming task progress.async for ev in stub.RunAgentInstruction(agent_pb2.RunAgentInstructionRequest(instruction="Open a calculator and compute 1+1")):
RunAgentInstructionAsyncAsynchronously submit the command and return the taskId.resp = await stub.RunAgentInstructionAsync(agent_pb2.RunAgentInstructionRequest(instruction="Create a new text document"))
GetAgentTaskStreamGet the streaming progress of the asynchronous task.async for ev in stub.GetAgentTaskStream(agent_pb2.GetAgentTaskStreamRequest(taskId=task_id)):
QueryTaskStatusCheck the task status and results.resp = await stub.QueryTaskStatus(agent_pb2.QueryTaskStatusRequest(taskId=task_id))
CancelTaskCancel the specified task.resp = await stub.CancelTask(agent_pb2.CancelTaskRequest(taskId=task_id))

For detailed parameters, please refer to the proto definition below.

/*
1. generate protobuf code
python3 -m grpc_tools.protoc -Igui_agents/proto \
  --python_out=gui_agents/proto/pb  \
  --grpc_python_out=gui_agents/proto/pb \
  --pyi_out=gui_agents/proto/pb \
  gui_agents/proto/agent.proto

2. resolve import path error:
sed -i 's/^import agent_pb2 as agent__pb2/from . import agent_pb2 as agent__pb2/' gui_agents/proto/pb/agent_pb2_grpc.py
*/

syntax = "proto3";

package lybic.agent;

option go_package = "github.com/lybic/lybic-sdk-go/agent";
option java_package = "com.lybic.agent";
option java_multiple_files = true;
option java_outer_classname = "AgentProto";
option py_generic_services = true;

import "google/protobuf/timestamp.proto";

service Agent {
  // get agent info
  rpc GetAgentInfo(GetAgentInfoRequest) returns (AgentInfo);

  // get agent config
  rpc GetGlobalCommonConfig(GetGlobalCommonConfigRequest) returns (CommonConfig);
  rpc GetCommonConfig(GetCommonConfigRequest) returns (CommonConfig);
  // set agent config
  rpc SetGlobalCommonConfig(SetGlobalCommonConfigRequest) returns (SetCommonConfigResponse);
  rpc SetGlobalCommonLLMConfig(SetGlobalCommonLLMConfigRequest) returns (LLMConfig);
  rpc SetGlobalGroundingLLMConfig(SetGlobalGroundingLLMConfigRequest) returns (LLMConfig);
  // set agent embedding
  rpc SetGlobalEmbeddingLLMConfig(SetGlobalEmbeddingLLMConfigRequest) returns (LLMConfig);

  // run agent sync
  rpc RunAgentInstruction(RunAgentInstructionRequest) returns (stream TaskStream);
  // run agent async
  rpc RunAgentInstructionAsync(RunAgentInstructionRequest) returns (RunAgentInstructionAsyncResponse);
  // get agent task stream
  rpc GetAgentTaskStream(GetAgentTaskStreamRequest) returns (stream GetAgentTaskStreamResponse);
  // query task status
  rpc QueryTaskStatus(QueryTaskStatusRequest)returns (QueryTaskStatusResponse);
  // cancel task
  rpc CancelTask(CancelTaskRequest) returns (CancelTaskResponse);
}

message SetGlobalCommonLLMConfigRequest {
  LLMConfig llmConfig = 1;
}

message SetGlobalEmbeddingLLMConfigRequest {
  LLMConfig llmConfig = 1;
}

message SetGlobalGroundingLLMConfigRequest {
  LLMConfig llmConfig = 1;
}

message SetGlobalCommonConfigRequest {
  CommonConfig commonConfig = 1;
}

message SetCommonConfigResponse {
  bool success = 1;
  string id = 2;
}

message GetAgentInfoRequest {
}
message GetGlobalCommonConfigRequest {
}

message GetCommonConfigRequest {
  string id = 1;
}

message AgentInfo {
  string version = 1;
  int32 maxConcurrentTasks = 2; // default 5
  string log_level = 3;
  optional string domain = 4;
}

message Sandbox {
  // sandbox id
  string id = 1;
  // sandbox name
  string name = 2;
  // sandbox description
  string description = 3;
  // sandbox shape
  string shapeName = 4;
  // is hardware accelerated encoding
  bool hardwareAcceleratedEncoding = 5;
  // sandbox os type
  SandboxOS os = 6;
  // virtualization
  string virtualization = 7; // KVM or Container
  // architecture
  string architecture = 8; // x86_64 or aarch64
}

enum SandboxOS {
  OSUNDEFINED = 0;
  WINDOWS = 1;
  LINUX = 2;
  ANDROID = 3;
}

message Authorization {
    string orgID = 1;
    string apiKey = 2;
    optional string apiEndpoint = 3; // default https://api.lybic.cn
}

message LLMConfig {
  string modelName = 1;
  optional string provider = 2; // if not specified, agent will automatically find the provider form the model name (support doubao,gemini,deepseek)
  optional string apiKey = 3;
  optional string apiEndpoint = 4;
}

message StageModelConfig{
  optional string webSearchEngine = 1;
  optional LLMConfig contextFusionModel = 2;
  optional LLMConfig subtaskPlannerModel = 3;
  optional LLMConfig trajReflectorModel = 4;
  optional LLMConfig memoryRetrivalModel = 5;
  optional LLMConfig groundingModel = 6;
  optional LLMConfig taskEvaluatorModel = 7;
  optional LLMConfig actionGeneratorModel = 8;
  optional LLMConfig actionGeneratorWithTakeoverModel = 9;
  optional LLMConfig fastActionGeneratorModel = 10;
  optional LLMConfig fastActionGeneratorWithTakeoverModel = 11;
  optional LLMConfig dagTranslatorModel = 12;
  optional LLMConfig embeddingModel = 13;
  optional LLMConfig queryFormulatorModel = 14;
  optional LLMConfig narrativeSummarizationModel = 15;
  optional LLMConfig textSpanModel = 16;
  optional LLMConfig episodeSummarizationModel = 17;
}

message CommonConfig {
  string id = 1;

  optional string backend = 2; // `lybic` for windows and linux or `lybic_mobile` for android
  InstanceMode mode = 3; // agent mode default is FAST
  optional int32 steps = 4; // default max steps is 50
  string platform = 5; // agent target plat。 this is not used now
  optional int32 taskTimeout = 6; // default 3600 (s)(1 hour)
  optional Authorization authorizationInfo = 7; // lybic authorization info
  optional StageModelConfig stageModelConfig = 8; // agent stage model config
}

enum InstanceMode {
  MODEUNDEFINED = 0;
  NORMAL = 1;
  FAST = 2;
}

message RunAgentInstructionRequest {
  //  natural language instruction
  string instruction = 1;

  optional Sandbox sandbox = 2; // if sandbox is not specified, agent will create a sandbox to execute the instruction
  optional CommonConfig runningConfig = 3; // if runningConfig is not specified, agent will use the default global config
  optional bool destroySandbox = 4; // if true, destroy the sandbox after task completion (default: false)
  optional string previousTaskId = 5; // if specified, restore conversation history from previous task to continue the context
}

message RunAgentInstructionAsyncResponse {
  string taskId = 1;
}

enum TaskStatus {
  TASKSTATUSUNDEFINED = 0;
  PENDING = 1;
  RUNNING = 2;
  SUCCESS = 3;
  FAILURE = 4;
  NOT_FOUND = 5;
  CANCELLED = 6;
}

message ExecutionStatistics {
  int32 steps = 1;
  int32 durationSeconds = 2;
  int64 inputTokens = 3;
  int64 outputTokens = 4;
  int64 totalTokens = 5;
  double cost = 6;
  string currencySymbol = 7;
}

message QueryTaskStatusRequest {
  string taskId = 1;
}

message QueryTaskStatusResponse {
  string taskId = 1;
  TaskStatus status = 2;
  string message = 3;
  string result = 4;
  optional Sandbox sandbox = 5;
  optional ExecutionStatistics executionStatistics = 6;
}

message GetAgentTaskStreamRequest {
  string taskId = 1;
}

message GetAgentTaskStreamResponse {
  TaskStream taskStream = 1;
}
message TaskStream{
  string taskId = 1;
  string stage = 2;
  string message = 3;
  google.protobuf.Timestamp timestamp = 4;
}

message CancelTaskRequest {
  string taskId = 1;
}

message CancelTaskResponse {
  string taskId = 1;
  bool success = 2;
  string message = 3;
}

Quick Start (Local)

LYBIC_API_KEY=your_key \
LYBIC_ORG_ID=your_org \
python -m gui_agents.grpc_app  # if module entry supported, else use installed script

Recommended: run inside Docker for isolation.

Docker Run

Basic start:

docker run --rm -it \
  -p 50051:50051 \
  --env-file gui_agents/.env \
  agenticlybic/guiagent /app/.venv/bin/lybic-guiagent-grpc

If you need enable Prometheus metrics:

docker run --rm -it \
  -p 50051:50051 -p 8000:8000 \
  -e ENABLE_PROMETHEUS=true -e PROMETHEUS_PORT=8000 \
  --env-file gui_agents/.env \
  agenticlybic/guiagent /app/.venv/bin/lybic-guiagent-grpc

Metrics endpoint: http://HOST:8000/metrics.

Core Environment Variables

VariablePurposeExample
LYBIC_API_KEYAuth to Lybic sandbox APIsk_live_...
LYBIC_ORG_IDOrganization scopeorg_123
LYBIC_PRECREATE_SIDAttach precreated sandboxSBX-XXXXXXXX
LYBIC_MAX_LIFE_SECONDSOverride sandbox lifetime3600
ENABLE_PROMETHEUSExpose metrics endpointtrue
PROMETHEUS_PORTMetrics port8000
TASK_STORAGE_BACKENDmemory or postgrespostgres
POSTGRES_CONNECTION_STRINGDB connect stringpostgresql://user:pwd@host:5432/db
Provider keys (Gemini/Ark etc.)Model access(see tools_config)

Optional Persistence (PostgreSQL)

Install extras:

pip install lybic-guiagents[postgres]
# or in Docker image already present

Set backend:

export TASK_STORAGE_BACKEND=postgres
export POSTGRES_CONNECTION_STRING=postgresql://user:password@db-host:5432/lybic_agent

Data stored: task metadata, status, history for recovery / analytics.

Docker Compose Example

version: "3.9"
services:
  agent-grpc:
    image: agenticlybic/guiagent:latest
    restart: unless-stopped
    ports:
      - "50051:50051"
      - "8000:8000"    # metrics
    env_file: gui_agents/.env
    environment:
      ENABLE_PROMETHEUS: "true"
      PROMETHEUS_PORT: "8000"
      TASK_STORAGE_BACKEND: "postgres"
      POSTGRES_CONNECTION_STRING: "postgresql://agent:agent@postgres:5432/agent"
    command: ["/app/.venv/bin/lybic-guiagent-grpc"]
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: agent
      POSTGRES_PASSWORD: agent
      POSTGRES_DB: agent
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata: {}

Kubernetes Deployment Snippet

apiVersion: apps/v1
kind: Deployment
metadata:
  name: lybic-agent-grpc
spec:
  replicas: 2
  selector:
    matchLabels:
      app: lybic-agent-grpc
  template:
    metadata:
      labels:
        app: lybic-agent-grpc
    spec:
      containers:
      - name: agent
        image: agenticlybic/guiagent:latest
        ports:
        - containerPort: 50051
        - containerPort: 8000
        env:
        - name: LYBIC_API_KEY
          valueFrom:
            secretKeyRef:
              name: lybic-secrets
              key: api_key
        - name: LYBIC_ORG_ID
          valueFrom:
            secretKeyRef:
              name: lybic-secrets
              key: org_id
        - name: ENABLE_PROMETHEUS
          value: "true"
        - name: PROMETHEUS_PORT
          value: "8000"
        - name: TASK_STORAGE_BACKEND
          value: postgres
        - name: POSTGRES_CONNECTION_STRING
          valueFrom:
            secretKeyRef:
              name: lybic-secrets
              key: pg_conn
        readinessProbe:
          tcpSocket:
            port: 50051
          initialDelaySeconds: 5
          periodSeconds: 10
        livenessProbe:
          tcpSocket:
            port: 50051
          initialDelaySeconds: 15
          periodSeconds: 20
---
apiVersion: v1
kind: Service
metadata:
  name: lybic-agent-grpc
spec:
  selector:
    app: lybic-agent-grpc
  ports:
  - port: 50051
    targetPort: 50051
  - port: 8000
    targetPort: 8000

Add Prometheus scrape job for :8000/metrics.

Client Usage (Python Async)

Streaming (RunAgentInstruction)

Returns live TaskStream events until completion.

import asyncio, grpc
from gui_agents.proto.pb import agent_pb2, agent_pb2_grpc

async def streaming_example():
    async with grpc.aio.insecure_channel("localhost:50051") as channel:
        stub = agent_pb2_grpc.AgentStub(channel)
        # (Optional) configure grounding/action models
        await stub.SetGlobalGroundingLLMConfig(agent_pb2.SetGlobalGroundingLLMConfigRequest(
            llmConfig=agent_pb2.LLMConfig(modelName="doubao-1-5-ui-tars-250428")
        ))
        await stub.SetGlobalCommonLLMConfig(agent_pb2.SetGlobalCommonLLMConfigRequest(
            llmConfig=agent_pb2.LLMConfig(modelName="claude-sonnet-4-20250514")
        ))
        async for ev in stub.RunAgentInstruction(agent_pb2.RunAgentInstructionRequest(
            instruction="Open a calculator and compute 1 + 1"
        )):
            print(f"[STREAM {ev.taskStream.stage}] {ev.taskStream.message}")

asyncio.run(streaming_example())

Async Lifecycle (RunAgentInstructionAsync + GetAgentTaskStream + QueryTaskStatus)

import asyncio, grpc
from gui_agents.proto.pb import agent_pb2, agent_pb2_grpc

async def lifecycle_example():
    async with grpc.aio.insecure_channel("localhost:50051") as channel:
        stub = agent_pb2_grpc.AgentStub(channel)
        # Start async task
        start = await stub.RunAgentInstructionAsync(agent_pb2.RunAgentInstructionRequest(
            instruction="Create a new text document and write today's date"
        ))
        task_id = start.taskId
        print("Started task", task_id)
        # Concurrent stream and polling
        async def stream_events():
            async for ev in stub.GetAgentTaskStream(agent_pb2.GetAgentTaskStreamRequest(taskId=task_id)):
                print(f"[STREAM {ev.taskStream.stage}] {ev.taskStream.message}")
        async def poll_status():
            while True:
                status = await stub.QueryTaskStatus(agent_pb2.QueryTaskStatusRequest(taskId=task_id))
                print("[STATUS]", status.status.name)
                if status.status in (agent_pb2.SUCCESS, agent_pb2.FAILURE, agent_pb2.CANCELLED):
                    print("Final result:", status.result)
                    if status.executionStatistics:
                        print("Steps:", status.executionStatistics.steps,
                              "Duration(s):", status.executionStatistics.durationSeconds,
                              "Tokens:", status.executionStatistics.totalTokens)
                    break
                await asyncio.sleep(4)
        await asyncio.gather(stream_events(), poll_status())

asyncio.run(lifecycle_example())

Cancellation

cancel_resp = await stub.CancelTask(agent_pb2.CancelTaskRequest(taskId=task_id))
print("Cancel success?", cancel_resp.success, cancel_resp.message)

Configuration Updates

# Update just grounding model
await stub.SetGlobalGroundingLLMConfig(agent_pb2.SetGlobalGroundingLLMConfigRequest(
    llmConfig=agent_pb2.LLMConfig(modelName="doubao-1-5-ui-tars-250428")
))
# Update action generator
await stub.SetGlobalCommonLLMConfig(agent_pb2.SetGlobalCommonLLMConfigRequest(
    llmConfig=agent_pb2.LLMConfig(modelName="claude-sonnet-4-20250514")
))
# Set full global config (mode FAST, max 40 steps)
await stub.SetGlobalCommonConfig(agent_pb2.SetGlobalCommonConfigRequest(
  commonConfig=agent_pb2.CommonConfig(
    id="global",
    backend="lybic",
    mode=agent_pb2.FAST,
    steps=40,
    authorizationInfo=agent_pb2.Authorization(orgID="org_123", apiKey="sk_live"),
    stageModelConfig=agent_pb2.StageModelConfig(
      groundingModel=agent_pb2.LLMConfig(modelName="doubao-1-5-ui-tars-250428"),
      actionGeneratorModel=agent_pb2.LLMConfig(modelName="claude-sonnet-4-20250514")
    )
  )
))

Query Task Status (Polling Only)

status = await stub.QueryTaskStatus(agent_pb2.QueryTaskStatusRequest(taskId=task_id))
print(status.status.name, status.result)
if status.executionStatistics:
    print("Cost", status.executionStatistics.cost, status.executionStatistics.currencySymbol)

Minimal One-Shot Helper

async def run_one_shot(instruction: str):
    async with grpc.aio.insecure_channel("localhost:50051") as channel:
        stub = agent_pb2_grpc.AgentStub(channel)
        async for ev in stub.RunAgentInstruction(agent_pb2.RunAgentInstructionRequest(instruction=instruction)):
            if ev.taskStream.stage == "final":
                print("Result:", ev.taskStream.message)

Best Practices

  1. Ephemeral Container Config: Run Docker without embedding API keys or model credentials; keep images secret-free.
  2. Per-Request Credentials: Pass authorizationInfo and per-stage LLMConfig (with apiKey if needed) in each RunAgentInstructionRequest.runningConfig; use global config only in trusted isolated deployments.
  3. Persistent Storage: Prefer PostgreSQL backend so task metadata & stats survive restarts and enable auditing.
  4. Horizontal Scaling: Even though one instance can run multiple tasks, deploy multiple replicas behind LB to avoid single point of failure.
  5. Immutable Defaults: Treat global CommonConfig as baseline; override per task to prevent cross-tenant leakage.
  6. Least Privilege: Separate keys per environment (dev/staging/prod); rotate & never bake prod keys into images.
  7. Observability: Enable Prometheus, aggregate logs, alert on spikes in FAILURE/CANCELLED or sandbox creation errors.
  8. Graceful Cancellation: Implement client-side timeouts and call CancelTask early to free sandbox resources.
  9. Version Pinning: Use image digests, avoid latest in production.
  10. Sandbox Strategy: Use precreated sandbox only for latency-critical tasks; otherwise allow auto creation for better isolation.

Scaling Patterns

  • Horizontal: multiple replicas behind a service; each replica manages independent sandbox instances.
  • Sharding: route tasks by project/org to dedicated deployment.
  • Persistence: enable PostgreSQL to recover task states after pod restarts.
  • Observability: scrape metrics, add log aggregation (stdout structured logs).

Security & Secrets

  • Store API keys in secret managers (K8s Secrets, HashiCorp Vault, AWS/GCP secret services).
  • Restrict network egress if using local backends.
  • Use separate service accounts per environment (dev/staging/prod).

Health & Readiness

  • gRPC TCP probe on 50051.
  • Optional custom health RPC (future) for deeper diagnostics.
  • Alert if sandbox creation error rate spikes.

Common Deployment Issues

IssueCauseFix
Sandbox not attachingMissing LYBIC_API_KEY / ORG or quota exceededVerify env & account quota
High cold start timeOn-demand sandbox creationPrecreate sandbox LYBIC_PRECREATE_SID or warm pool
Task history lostUsing memory backendSwitch to postgres backend
Metrics emptyENABLE_PROMETHEUS not setSet env + open port 8000

Version Upgrades

Pull new image & roll restart:

kubectl set image deployment/lybic-agent-grpc agent=agenticlybic/guiagent:latest

Pin versions for reproducibility (avoid latest in prod).

Next Steps

  • Integrate with MCP server for LLM-driven instruction flows.
  • Add tracing (OpenTelemetry) if enabled in future releases.
  • Build higher-level orchestrator coordinating multiple agent replicas.

On this page