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:
| Method | Purpose | Example |
|---|---|---|
| GetAgentInfo | Retrieve Agent version and capabilities information. | resp = stub.GetAgentInfo(agent_pb2.GetAgentInfoRequest()) |
| GetGlobalCommonConfig | Get global general configuration. | resp = stub.GetGlobalCommonConfig(agent_pb2.GetGlobalCommonConfigRequest()) |
| SetGlobalCommonConfig | Set global general configuration. | resp = stub.SetGlobalCommonConfig(agent_pb2.SetGlobalCommonConfigRequest(commonConfig=...)) |
| SetGlobalCommonLLMConfig/SetGlobalGroundingLLMConfig/SetGlobalEmbeddingLLMConfig | Configure global LLM/embedding/grounding models. Refer to Model Support & Configuration Reference | resp = stub.SetGlobalCommonLLMConfig(agent_pb2.SetGlobalCommonLLMConfigRequest(llmConfig=...)) |
| RunAgentInstruction | Execute 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")): |
| RunAgentInstructionAsync | Asynchronously submit the command and return the taskId. | resp = await stub.RunAgentInstructionAsync(agent_pb2.RunAgentInstructionRequest(instruction="Create a new text document")) |
| GetAgentTaskStream | Get the streaming progress of the asynchronous task. | async for ev in stub.GetAgentTaskStream(agent_pb2.GetAgentTaskStreamRequest(taskId=task_id)): |
| QueryTaskStatus | Check the task status and results. | resp = await stub.QueryTaskStatus(agent_pb2.QueryTaskStatusRequest(taskId=task_id)) |
| CancelTask | Cancel 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 scriptRecommended: 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-grpcIf 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-grpcMetrics endpoint: http://HOST:8000/metrics.
Core Environment Variables
| Variable | Purpose | Example |
|---|---|---|
LYBIC_API_KEY | Auth to Lybic sandbox API | sk_live_... |
LYBIC_ORG_ID | Organization scope | org_123 |
LYBIC_PRECREATE_SID | Attach precreated sandbox | SBX-XXXXXXXX |
LYBIC_MAX_LIFE_SECONDS | Override sandbox lifetime | 3600 |
ENABLE_PROMETHEUS | Expose metrics endpoint | true |
PROMETHEUS_PORT | Metrics port | 8000 |
TASK_STORAGE_BACKEND | memory or postgres | postgres |
POSTGRES_CONNECTION_STRING | DB connect string | postgresql://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 presentSet backend:
export TASK_STORAGE_BACKEND=postgres
export POSTGRES_CONNECTION_STRING=postgresql://user:password@db-host:5432/lybic_agentData 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: 8000Add 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
- Ephemeral Container Config: Run Docker without embedding API keys or model credentials; keep images secret-free.
- Per-Request Credentials: Pass
authorizationInfoand per-stageLLMConfig(with apiKey if needed) in each RunAgentInstructionRequest.runningConfig; use global config only in trusted isolated deployments. - Persistent Storage: Prefer PostgreSQL backend so task metadata & stats survive restarts and enable auditing.
- Horizontal Scaling: Even though one instance can run multiple tasks, deploy multiple replicas behind LB to avoid single point of failure.
- Immutable Defaults: Treat global CommonConfig as baseline; override per task to prevent cross-tenant leakage.
- Least Privilege: Separate keys per environment (dev/staging/prod); rotate & never bake prod keys into images.
- Observability: Enable Prometheus, aggregate logs, alert on spikes in FAILURE/CANCELLED or sandbox creation errors.
- Graceful Cancellation: Implement client-side timeouts and call CancelTask early to free sandbox resources.
- Version Pinning: Use image digests, avoid
latestin production. - 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
| Issue | Cause | Fix |
|---|---|---|
| Sandbox not attaching | Missing LYBIC_API_KEY / ORG or quota exceeded | Verify env & account quota |
| High cold start time | On-demand sandbox creation | Precreate sandbox LYBIC_PRECREATE_SID or warm pool |
| Task history lost | Using memory backend | Switch to postgres backend |
| Metrics empty | ENABLE_PROMETHEUS not set | Set env + open port 8000 |
Version Upgrades
Pull new image & roll restart:
kubectl set image deployment/lybic-agent-grpc agent=agenticlybic/guiagent:latestPin 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.