diff --git a/docs/agentcube/docs/api-reference.md b/docs/agentcube/docs/api-reference.md new file mode 100644 index 000000000..763bf4df5 --- /dev/null +++ b/docs/agentcube/docs/api-reference.md @@ -0,0 +1,514 @@ +--- +sidebar_position: 5 +--- + +# API Reference + +REST APIs for all AgentCube components. All bodies are JSON (`Content-Type: application/json`) unless noted. + +--- + +## AgentCube Router API + +The Router is the primary entry point for all client traffic. It validates authentication, manages session state, and proxies requests to the correct sandbox. + +**Base URL**: `http://:` + +--- + +### Invoke AgentRuntime + +Sends a request to a named `AgentRuntime`'s sandbox. If no `x-agentcube-session-id` header is provided, a new session (and sandbox) is created automatically. + +``` +POST /v1/namespaces/{namespace}/agent-runtimes/{name}/invocations/*path +``` + +**Path Parameters** + +| Parameter | Description | +| ----------- | ------------------------------------------------------------- | +| `namespace` | Kubernetes namespace where the `AgentRuntime` resource exists | +| `name` | Name of the `AgentRuntime` resource | +| `*path` | Any sub-path forwarded to the agent container | + +**Request Headers** + +| Header | Required | Description | +| ------------------------ | ----------- | ------------------------------------------------------------------- | +| `x-agentcube-session-id` | No | Session ID from a previous invocation. Omit to start a new session. | +| `Authorization` | Conditional | Bearer JWT if external OIDC auth is configured on the Router. | + +**Response Headers** + +| Header | Description | +| ------------------------ | ---------------------------------------------------------------------- | +| `x-agentcube-session-id` | Always present. The session ID for this interaction (new or existing). | + +**Example — New Session:** + +```bash +curl -X POST \ + http://agentcube-router:8080/v1/namespaces/default/agent-runtimes/my-agent/invocations/ \ + -H "Content-Type: application/json" \ + -d '{"message": "Hello, Agent!"}' +# Response header: x-agentcube-session-id: abc123def456 +``` + +**Example — Resume Session:** + +```bash +curl -X POST \ + http://agentcube-router:8080/v1/namespaces/default/agent-runtimes/my-agent/invocations/ \ + -H "x-agentcube-session-id: abc123def456" \ + -H "Content-Type: application/json" \ + -d '{"message": "Continue the task..."}' +``` + +--- + +### Invoke CodeInterpreter + +Sends a request to a named `CodeInterpreter`'s sandbox. + +``` +POST /v1/namespaces/{namespace}/code-interpreters/{name}/invocations/*path +``` + +**Path Parameters** + +| Parameter | Description | +| ----------- | --------------------------------------------------------------------------- | +| `namespace` | Kubernetes namespace where the `CodeInterpreter` resource exists | +| `name` | Name of the `CodeInterpreter` resource | +| `*path` | Sub-path forwarded to the PicoD daemon (e.g., `/api/execute`, `/api/files`) | + +**Request / Response Headers**: Same as AgentRuntime invocation above. + +--- + +## Workload Manager API + +The Workload Manager is an **internal** control plane service. It is called by the Router — not directly by end users. These endpoints are documented here for operators and developers who need to understand or debug the system. + +**Base URL**: `http://:8080` + +--- + +### Create AgentRuntime Session + +Provisions a new sandbox for an `AgentRuntime` resource. + +``` +POST /v1/agent-runtime +``` + +**Request Body:** + +```json +{ + "namespace": "default", + "name": "my-agent" +} +``` + +| Field | Type | Required | Description | +| ----------- | -------- | -------- | ---------------------------------- | +| `namespace` | `string` | Yes | Namespace of the `AgentRuntime` CR | +| `name` | `string` | Yes | Name of the `AgentRuntime` CR | + +**Response Body (200 OK):** + +```json +{ + "sessionId": "7f8b9c0d1e2f3g4h5i6j7k8l9m0n", + "sandboxId": "abc123def456ghi789jkl012mno345", + "sandboxName": "my-sandbox", + "entryPoints": [ + { + "path": "/", + "protocol": "http", + "endpoint": "10.0.0.5:8080" + } + ] +} +``` + +--- + +### Delete AgentRuntime Session + +Deletes a sandbox and cleans up the associated session from the registry. + +``` +DELETE /v1/agent-runtime/sessions/{sessionId} +``` + +**Path Parameters** + +| Parameter | Description | +| ----------- | --------------------------- | +| `sessionId` | The session ID to terminate | + +**Response**: `200 OK` on success. + +--- + +### Create CodeInterpreter Session + +Provisions a new sandbox for a `CodeInterpreter` resource. If `warmPoolSize > 0`, an already-warmed Pod is adopted. + +``` +POST /v1/code-interpreter +``` + +**Request Body:** + +```json +{ + "namespace": "default", + "name": "my-interpreter" +} +``` + +**Response Body (200 OK):** + +```json +{ + "sessionId": "7f8b9c0d1e2f3g4h5i6j7k8l9m0n", + "sandboxId": "abc123def456ghi789jkl012mno345", + "sandboxName": "my-sandbox", + "entryPoints": [ + { + "path": "/", + "protocol": "http", + "endpoint": "10.0.0.6:8080" + } + ] +} +``` + +--- + +### Delete CodeInterpreter Session + +``` +DELETE /v1/code-interpreter/sessions/{sessionId} +``` + +**Response**: `200 OK` on success. + +--- + +## PicoD (Sandbox Daemon) API + +PicoD is the lightweight RESTful daemon running **inside every CodeInterpreter sandbox**. It handles command execution and file transfers. + +**Base URL**: `http://:8080` + +:::note +PicoD is accessed indirectly through the AgentCube Router. Direct access is only needed for debugging or local development. +::: + +--- + +### Initialize Sandbox + +**One-time endpoint** called by the Workload Manager when a sandbox is allocated to a user. Injects the user's session public key, making the sandbox exclusively accessible to that user. + +``` +POST /init +``` + +**Request Headers:** + +```http +Authorization: Bearer +``` + +The `` is a JWT signed by the Workload Manager's bootstrap private key. Its claims contain the user's session public key: + +```json +{ + "session_public_key": "LS0tLS1CRUdJTi...", + "iat": 1732531800, + "exp": 1732553400 +} +``` + +**Response (200 OK):** + +```json +{ + "message": "Server initialized successfully. This PicoD instance is now locked to your public key." +} +``` + +**Errors:** + +- `401 Unauthorized` — Invalid or expired init JWT. +- `409 Conflict` — Sandbox is already initialized. + +--- + +### Execute Command + +Executes a shell command inside the sandbox and returns the output. + +``` +POST /api/execute +``` + +**Request Headers:** + +```http +Authorization: Bearer +Content-Type: application/json +``` + +**Request Body:** + +```json +{ + "command": ["python3", "-c", "print('Hello World')"], + "timeout": "30s", + "working_dir": "/workspace", + "env": { + "MY_VAR": "value" + } +} +``` + +| Field | Type | Required | Description | +| ------------- | ------------------- | -------- | ------------------------------------------------------------ | +| `command` | `[]string` | Yes | Command and arguments as an array | +| `timeout` | `string` | No | Execution timeout (e.g., `"30s"`, `"5m"`). Default: `"30s"`. | +| `working_dir` | `string` | No | Working directory for the command. Default: `/` | +| `env` | `map[string]string` | No | Additional environment variables for the process | + +**Response (200 OK):** + +```json +{ + "stdout": "Hello World\n", + "stderr": "", + "exit_code": 0, + "duration": 0.12, + "start_time": "2025-11-18T10:30:00Z", + "end_time": "2025-11-18T10:30:00.12Z" +} +``` + +**Error Response (RFC 7807):** + +```json +{ + "type": "https://example.com/errors/unauthorized", + "title": "Unauthorized", + "status": 401, + "detail": "Invalid token" +} +``` + +--- + +### Upload File + +Uploads a file to the sandbox filesystem. Supports two content formats. + +``` +POST /api/files +``` + +**Request Headers:** + +```http +Authorization: Bearer +``` + +**Option 1: Multipart Form Data** (recommended for binary files) + +```http +Content-Type: multipart/form-data; boundary=----WebKitFormBoundary + +------WebKitFormBoundary +Content-Disposition: form-data; name="path" +/workspace/data.csv +------WebKitFormBoundary +Content-Disposition: form-data; name="file"; filename="data.csv" +Content-Type: text/csv + +[file content] +------WebKitFormBoundary +Content-Disposition: form-data; name="mode" +0644 +------WebKitFormBoundary-- +``` + +**Option 2: JSON with Base64** (for text files or API convenience) + +```json +{ + "path": "/workspace/script.py", + "content": "cHJpbnQoJ2hlbGxvJyk=", + "mode": "0644" +} +``` + +| Field | Type | Description | +| --------- | -------- | --------------------------------------------------------------- | +| `path` | `string` | Absolute path inside the sandbox where the file should be saved | +| `content` | `string` | Base64-encoded file content (JSON mode only) | +| `mode` | `string` | Unix file permissions (e.g., `"0644"`) | + +**Response (200 OK):** + +```json +{ + "path": "/workspace/script.py", + "size": 1024, + "mode": "0644", + "modified": "2025-11-18T10:30:00Z" +} +``` + +--- + +### Download File + +Downloads a file from the sandbox filesystem. + +``` +GET /api/files/{path} +``` + +**Path Parameters:** + +| Parameter | Description | +| --------- | ---------------------------------------------------------------- | +| `path` | Absolute path inside the sandbox (e.g., `workspace/result.json`) | + +**Request Headers:** + +```http +Authorization: Bearer +``` + +**Response:** + +```http +HTTP/1.1 200 OK +Content-Type: text/plain +Content-Length: 1024 +Content-Disposition: attachment; filename="result.json" + +[file content] +``` + +For binary files, the appropriate `Content-Type` is set (e.g., `application/octet-stream`, `image/png`). + +--- + +### List Files + +Lists files in a directory within the sandbox. + +``` +GET /api/files?path={directory} +``` + +**Query Parameters:** + +| Parameter | Required | Description | +| --------- | -------- | ------------------------------------- | +| `path` | No | Directory path to list (default: `/`) | + +**Request Headers:** + +```http +Authorization: Bearer +``` + +**Response (200 OK):** + +```json +[ + { + "name": "result.json", + "path": "/workspace/result.json", + "size": 1024, + "is_dir": false, + "modified": "2025-11-18T10:30:00Z", + "mode": "0644" + }, + { + "name": "data", + "path": "/workspace/data", + "is_dir": true, + "modified": "2025-11-18T10:00:00Z" + } +] +``` + +--- + +### Health Check + +Returns the health status of the PicoD daemon. No authentication required. + +``` +GET /health +``` + +**Response (200 OK):** + +```json +{ + "status": "ok", + "uptime": "2h34m12s" +} +``` + +--- + +## Python SDK Reference + +The AgentCube Python SDK provides a high-level wrapper over the Workload Manager and PicoD APIs. + +### `CodeInterpreterClient` + +**Constructor Parameters:** + +| Parameter | Type | Default | Description | +| ---------------------- | ------ | -------------------------- | ---------------------------------------------------- | +| `name` | `str` | `"simple-codeinterpreter"` | Name of the `CodeInterpreter` CRD | +| `namespace` | `str` | `"default"` | Kubernetes namespace | +| `ttl` | `int` | `3600` | Session time-to-live in seconds | +| `workload_manager_url` | `str` | `None` | Workload Manager URL (or set `WORKLOAD_MANAGER_URL`) | +| `router_url` | `str` | `None` | Router URL (or set `ROUTER_URL`) | +| `auth_token` | `str` | `None` | Auth token (falls back to K8s ServiceAccount token) | +| `session_id` | `str` | `None` | Resume an existing session | +| `verbose` | `bool` | `False` | Enable debug logging | + +**Methods:** + +| Method | Signature | Description | +| ----------------- | ------------------------------------------------------ | ----------------------------------------------------- | +| `execute_command` | `(command: str) -> str` | Run a shell command and return stdout | +| `run_code` | `(language: str, code: str, timeout: int = 30) -> str` | Execute a code block. Supported: `"python"`, `"bash"` | +| `upload_file` | `(local_path: str, remote_path: str) -> None` | Upload a local file to the sandbox | +| `download_file` | `(remote_path: str, local_path: str) -> str` | Download a file from the sandbox | +| `write_file` | `(content: str, remote_path: str) -> None` | Write string content directly to a remote path | +| `list_files` | `(path: str = "/") -> list` | List files in a sandbox directory | +| `stop` | `() -> None` | Terminate the session and free the sandbox | + +**Context Manager (recommended):** + +```python +from agentcube import CodeInterpreterClient + +with CodeInterpreterClient(name="my-interpreter") as client: + output = client.run_code("python", "print('Hello from AgentCube!')") + print(output) +# Session is automatically stopped when the `with` block exits +``` diff --git a/docs/agentcube/docs/configuration.md b/docs/agentcube/docs/configuration.md new file mode 100644 index 000000000..e5c968c1c --- /dev/null +++ b/docs/agentcube/docs/configuration.md @@ -0,0 +1,288 @@ +--- +sidebar_position: 4 +--- + +# Configuration Reference + +Helm chart values, CRD fields, and SDK environment variables — all in one place. + +--- + +## Helm Chart Values + +Install or upgrade AgentCube using the Helm chart in `manifests/charts/base`. Pass overrides with `--set key=value` or via a custom `values.yaml`. + +### Redis + +AgentCube requires a Redis (or Valkey) instance for session state synchronization. + +| Parameter | Type | Default | Description | +| ------------------ | -------- | ------------ | ----------------------------------------------------------------------------------------------------------- | +| `redis.addr` | `string` | `""` | **Required.** Redis server address in `host:port` format (e.g., `redis.agentcube.svc.cluster.local:6379`). | +| `redis.password` | `string` | `""` | Redis password. Creates a chart-managed Kubernetes Secret. Do **not** set together with `redis.secretName`. | +| `redis.secretName` | `string` | `""` | Name of an existing Kubernetes Secret containing the Redis password. **Recommended for production.** | +| `redis.secretKey` | `string` | `"password"` | The key inside the Secret (chart-managed or external) that holds the password. | + +**Example (production with existing Secret):** + +```bash +kubectl -n agentcube create secret generic agentcube-redis \ + --from-literal=password='YOUR_SECURE_PASSWORD' + +helm install agentcube ./manifests/charts/base \ + --set redis.addr="redis.agentcube.svc.cluster.local:6379" \ + --set redis.secretName="agentcube-redis" +``` + +--- + +### AgentCube Router + +The Router is the data plane component that handles all incoming invocation requests. + +| Parameter | Type | Default | Description | +| ---------------------------------- | -------- | ------------------------------------- | ------------------------------------------------------------------ | +| `router.replicas` | `int` | `1` | Number of Router pod replicas. Increase for high availability. | +| `router.image.repository` | `string` | `ghcr.io/volcano-sh/agentcube-router` | Container image repository. | +| `router.image.tag` | `string` | `"latest"` | Container image tag. Pin this to a specific version in production. | +| `router.image.pullPolicy` | `string` | `IfNotPresent` | Kubernetes image pull policy (`Always`, `Never`, `IfNotPresent`). | +| `router.service.type` | `string` | `ClusterIP` | Kubernetes Service type (`ClusterIP`, `NodePort`, `LoadBalancer`). | +| `router.service.port` | `int` | `8080` | Port exposed by the Service. | +| `router.service.targetPort` | `int` | `8080` | Port the container listens on. | +| `router.resources.limits.cpu` | `string` | `500m` | CPU limit for the Router container. | +| `router.resources.limits.memory` | `string` | `512Mi` | Memory limit for the Router container. | +| `router.resources.requests.cpu` | `string` | `100m` | CPU request for the Router container. | +| `router.resources.requests.memory` | `string` | `128Mi` | Memory request for the Router container. | +| `router.serviceAccountName` | `string` | `"agentcube-router"` | Kubernetes ServiceAccount name for the Router. | +| `router.extraEnv` | `list` | `[]` | Additional environment variables to inject into the Router pods. | +| `router.config` | `object` | `{}` | Extra configuration map entries for the Router. | + +#### Router JWT / OIDC Authentication + +When `router.jwt.issuerUrl` is set, the Router validates all incoming API requests against an external OIDC identity provider (Keycloak, Okta, Auth0, Dex, etc.). + +| Parameter | Type | Default | Description | +| ------------------------- | -------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| `router.jwt.issuerUrl` | `string` | `""` | OIDC issuer URL. When set, enables external JWT validation. | +| `router.jwt.audience` | `string` | `"agentcube-api"` | Expected `aud` claim value in access tokens. | +| `router.jwt.roleClaim` | `string` | `""` | **Required if `issuerUrl` is set.** JSON path to the roles array in the JWT (e.g., `"realm_access.roles"` for Keycloak, `"groups"` for Okta). | +| `router.jwt.requiredRole` | `string` | `""` | **Required if `issuerUrl` is set.** The role required to access API endpoints (e.g., `"sandbox:invoke"`). | + +**Example (Keycloak):** + +```yaml +router: + jwt: + issuerUrl: "http://keycloak.agentcube-system.svc:8080/realms/agentcube" + audience: "agentcube-api" + roleClaim: "realm_access.roles" + requiredRole: "sandbox:invoke" +``` + +--- + +### Workload Manager + +The Workload Manager is the control plane component that manages sandbox lifecycle. + +| Parameter | Type | Default | Description | +| ------------------------------------------- | -------- | ------------------------------------ | ---------------------------------------- | +| `workloadmanager.replicas` | `int` | `1` | Number of Workload Manager pod replicas. | +| `workloadmanager.image.repository` | `string` | `ghcr.io/volcano-sh/workloadmanager` | Container image repository. | +| `workloadmanager.image.tag` | `string` | `"latest"` | Container image tag. | +| `workloadmanager.image.pullPolicy` | `string` | `IfNotPresent` | Kubernetes image pull policy. | +| `workloadmanager.service.type` | `string` | `ClusterIP` | Kubernetes Service type. | +| `workloadmanager.service.port` | `int` | `8080` | Service port. | +| `workloadmanager.resources.limits.cpu` | `string` | `500m` | CPU limit. | +| `workloadmanager.resources.limits.memory` | `string` | `512Mi` | Memory limit. | +| `workloadmanager.resources.requests.cpu` | `string` | `100m` | CPU request. | +| `workloadmanager.resources.requests.memory` | `string` | `128Mi` | Memory request. | +| `workloadmanager.extraEnv` | `list` | `[]` | Additional environment variables. | + +--- + +### Volcano Scheduler (Optional) + +AgentCube can leverage the Volcano agent scheduler for advanced AI workload placement. Disabled by default. + +| Parameter | Type | Default | Description | +| ------------------------------------ | -------- | --------------------------------------- | ---------------------------------------------- | +| `volcano.scheduler.enabled` | `bool` | `false` | Whether to deploy the Volcano agent scheduler. | +| `volcano.scheduler.replicas` | `int` | `1` | Number of scheduler pod replicas. | +| `volcano.scheduler.image.repository` | `string` | `ghcr.io/volcano-sh/vc-agent-scheduler` | Scheduler image repository. | +| `volcano.scheduler.image.tag` | `string` | `"latest"` | Scheduler image tag. | + +--- + +### SPIRE (Internal mTLS Identity) — Optional + +AgentCube supports [SPIRE](https://spiffe.io/) for zero-trust, mTLS-based communication between all internal components. + +| Parameter | Type | Default | Description | +| ------------------------------------- | -------- | --------------------- | --------------------------------------------------------------------------------------- | +| `spire.enabled` | `bool` | `false` | Whether to enable SPIRE for internal workload identity. | +| `spire.trustDomain` | `string` | `"cluster.local"` | SPIFFE trust domain for the cluster. | +| `spire.clusterName` | `string` | `"agentcube-cluster"` | SPIRE cluster name identifier. | +| `spire.server.ca.ttl` | `string` | `"24h"` | Upstream CA certificate TTL. | +| `spire.server.ca.x509SvidDefaultTtl` | `string` | `"1h"` | Default X.509 SVID TTL. | +| `spire.agent.insecureBootstrap` | `bool` | `false` | For local dev clusters (kind/minikube). Set to `true` to skip attestation verification. | +| `spire.agent.skipKubeletVerification` | `bool` | `false` | For local dev clusters. Skip kubelet certificate verification. | + +**Example (local dev cluster):** + +```bash +helm install agentcube ./manifests/charts/base \ + --set spire.enabled=true \ + --set spire.agent.insecureBootstrap=true \ + --set spire.agent.skipKubeletVerification=true +``` + +--- + +## CRD Reference: AgentRuntime + +The `AgentRuntime` CRD defines a template for long-running, conversational agent sandboxes. + +**API Group**: `runtime.agentcube.volcano.sh/v1alpha1` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | ----------------- | -------- | ------- | ------------------------------------------------------ | +| `targetPort` | `[]TargetPort` | Yes | — | List of ports/paths the agent runtime exposes. | +| `podTemplate` | `SandboxTemplate` | Yes | — | Template for the sandbox Pod. | +| `sessionTimeout` | `Duration` | No | `15m` | Inactivity duration after which a session is paused. | +| `maxSessionDuration` | `Duration` | No | `8h` | Maximum lifetime of a session, regardless of activity. | + +### TargetPort Fields + +| Field | Type | Required | Default | Description | +| ------------ | -------- | -------- | ------- | --------------------------------------------------- | +| `pathPrefix` | `string` | No | — | URL path prefix routed to this port (e.g., `/api`). | +| `name` | `string` | No | — | Optional human-readable name for this port. | +| `port` | `uint32` | Yes | — | Port number the agent container listens on. | +| `protocol` | `string` | Yes | `HTTP` | Protocol type. Allowed values: `HTTP`, `HTTPS`. | + +### SandboxTemplate (AgentRuntime) + +| Field | Type | Required | Description | +| ------------- | ------------------- | -------- | ------------------------------------------------------------ | +| `labels` | `map[string]string` | No | Labels to apply to the sandbox Pod. | +| `annotations` | `map[string]string` | No | Annotations to apply to the sandbox Pod. | +| `spec` | `corev1.PodSpec` | Yes | Full Kubernetes Pod specification for the sandbox container. | + +**Example:** + +```yaml +apiVersion: runtime.agentcube.volcano.sh/v1alpha1 +kind: AgentRuntime +metadata: + name: my-agent + namespace: default +spec: + targetPort: + - pathPrefix: "/" + port: 8080 + protocol: "HTTP" + podTemplate: + spec: + containers: + - name: agent + image: my-registry/my-agent:latest + resources: + limits: + cpu: "1" + memory: "1Gi" + sessionTimeout: "30m" + maxSessionDuration: "4h" +``` + +--- + +## CRD Reference: CodeInterpreter + +The `CodeInterpreter` CRD is optimized for short-lived, secure code execution sessions. + +**API Group**: `runtime.agentcube.volcano.sh/v1alpha1` + +### Spec Fields + +| Field | Type | Required | Default | Description | +| -------------------- | -------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------- | +| `ports` | `[]TargetPort` | No | — | Ports the code interpreter exposes (e.g., `/execute`, `/files`). Defaults to using AgentCube's PicoD. | +| `template` | `CodeInterpreterSandboxTemplate` | Yes | — | Sandbox configuration for the code interpreter. | +| `sessionTimeout` | `Duration` | No | `15m` | Duration of inactivity before the session is eligible for cleanup. | +| `maxSessionDuration` | `Duration` | No | `8h` | Maximum session lifetime. | +| `warmPoolSize` | `int32` | No | — | Number of pre-warmed sandbox Pods to maintain. Reduces cold-start latency. | +| `authMode` | `string` | No | `picod` | Authentication mode. `picod` injects RSA public key auth; `none` disables auth injection for custom images. | + +### CodeInterpreterSandboxTemplate Fields + +| Field | Type | Required | Description | +| ------------------ | ----------------------------- | -------- | ----------------------------------------------------------------------------------- | +| `image` | `string` | Yes | Container image for the code interpreter (e.g., `ghcr.io/volcano-sh/picod:latest`). | +| `imagePullPolicy` | `string` | No | Image pull policy (`Always`, `Never`, `IfNotPresent`). | +| `imagePullSecrets` | `[]LocalObjectReference` | No | Secrets for pulling private images. | +| `runtimeClassName` | `string` | No | Kubernetes RuntimeClass for hardware-level isolation (e.g., `kata-qemu`). | +| `command` | `[]string` | No | Override the container's entrypoint command. | +| `args` | `[]string` | No | Arguments passed to the entrypoint. | +| `environment` | `[]corev1.EnvVar` | No | Environment variables to set in the sandbox. | +| `resources` | `corev1.ResourceRequirements` | No | CPU and memory limits and requests. | +| `labels` | `map[string]string` | No | Labels to apply to the sandbox Pod. | +| `annotations` | `map[string]string` | No | Annotations to apply to the sandbox Pod. | + +**Example:** + +```yaml +apiVersion: runtime.agentcube.volcano.sh/v1alpha1 +kind: CodeInterpreter +metadata: + name: python-interpreter + namespace: default +spec: + warmPoolSize: 2 + authMode: "picod" + template: + image: ghcr.io/volcano-sh/picod:latest + args: + - --workspace=/root + resources: + limits: + cpu: "500m" + memory: "512Mi" + requests: + cpu: "100m" + memory: "128Mi" + sessionTimeout: "15m" + maxSessionDuration: "8h" +``` + +--- + +## Python SDK Environment Variables + +When using the `agentcube` Python SDK, these environment variables configure the connection to AgentCube services: + +| Variable | Required | Description | +| ---------------------- | ---------------------------- | -------------------------------------------------------------------- | +| `WORKLOAD_MANAGER_URL` | Yes (if not passed directly) | URL of the Workload Manager service (e.g., `http://localhost:8080`). | +| `ROUTER_URL` | Yes (if not passed directly) | URL of the AgentCube Router service (e.g., `http://localhost:8081`). | + +Set them before running your Python code: + +```bash +export WORKLOAD_MANAGER_URL="http://localhost:8080" +export ROUTER_URL="http://localhost:8081" +``` + +Or pass them directly when constructing the client: + +```python +from agentcube import CodeInterpreterClient + +client = CodeInterpreterClient( + name="my-interpreter", + workload_manager_url="http://localhost:8080", + router_url="http://localhost:8081" +) +``` diff --git a/docs/agentcube/docs/developer-guide/code-interpreter-python-sdk.md b/docs/agentcube/docs/developer-guide/code-interpreter-python-sdk.md new file mode 100644 index 000000000..90bc7a77b --- /dev/null +++ b/docs/agentcube/docs/developer-guide/code-interpreter-python-sdk.md @@ -0,0 +1,311 @@ +--- +sidebar_position: 7 +--- + +# Python SDK Guide + +The `agentcube` Python SDK wraps the Workload Manager and PicoD APIs into a simple client. It manages session lifecycle, RSA key generation, and JWT signing automatically. + +## Prerequisites + +Before you begin, ensure your environment meets the following requirements: + +- **Python**: Version 3.10 or later +- **Network Access**: Access to the Workload Manager (Control Plane) and Router (Data Plane) +- **AgentCube deployed**: Follow the [Getting Started Guide](../getting-started.md) to set up AgentCube on your cluster + +### Install the SDK + +```bash +pip install agentcube-sdk +``` + +### Set Up Access + +For local development, use port-forwarding: + +```bash +# Terminal 1: Forward the Workload Manager +kubectl port-forward -n agentcube svc/workloadmanager 8080:8080 + +# Terminal 2: Forward the Router +kubectl port-forward -n agentcube svc/agentcube-router 8081:8080 +``` + +Then set environment variables: + +```bash +export WORKLOAD_MANAGER_URL="http://localhost:8080" +export ROUTER_URL="http://localhost:8081" +``` + +--- + +## 1. Initialize the Client + +The `CodeInterpreterClient` is the main entry point. Use it as a context manager (recommended) to ensure sessions are automatically cleaned up. + +### Configuration Parameters + +| Parameter | Type | Default | Description | +| ---------------------- | ------ | -------------------------- | ---------------------------------------------------------------- | +| `name` | `str` | `"simple-codeinterpreter"` | Name of the `CodeInterpreter` CRD template | +| `namespace` | `str` | `"default"` | Kubernetes namespace where the CRD exists | +| `ttl` | `int` | `3600` | Session time-to-live in seconds | +| `workload_manager_url` | `str` | `None` | Control Plane URL (falls back to `WORKLOAD_MANAGER_URL` env var) | +| `router_url` | `str` | `None` | Data Plane Router URL (falls back to `ROUTER_URL` env var) | +| `auth_token` | `str` | `None` | Auth token (falls back to Kubernetes ServiceAccount token) | +| `session_id` | `str` | `None` | Resume an existing session instead of creating a new one | +| `verbose` | `bool` | `False` | Enable debug logging | + +### Environment Variables + +| Variable | Description | +| ---------------------- | ---------------------------------------------------------- | +| `WORKLOAD_MANAGER_URL` | Control Plane URL (required if not passed as argument) | +| `ROUTER_URL` | Data Plane Router URL (required if not passed as argument) | + +### Example: Basic Initialization + +```python +from agentcube import CodeInterpreterClient + +# Initialize using a context manager (recommended) +with CodeInterpreterClient(name="my-interpreter", verbose=True) as client: + print(f"Session ID: {client.session_id}") + # ... use the client +# Session is automatically stopped here +``` + +--- + +## 2. Execute Commands and Code + +The SDK provides distinct methods for running shell commands and executing code blocks. + +### Run Shell Commands + +Use `execute_command` to run system operations on the remote agent. + +```python +with CodeInterpreterClient(name="my-interpreter") as client: + # Check current user and working directory + output = client.execute_command("whoami && pwd") + print(output) + + # Install a package + client.execute_command("pip install numpy") +``` + +### Run Code + +Use `run_code` to execute a code block. Supported languages: `"python"` (or `"py"`, `"python3"`) and `"bash"` (or `"sh"`). + +```python +with CodeInterpreterClient(name="my-interpreter") as client: + # Run Python code + script = """ +import math +results = [math.sqrt(i) for i in range(1, 6)] +print(results) +""" + result = client.run_code(language="python", code=script) + print(result) + # Output: [1.0, 1.4142135623730951, 1.7320508075688772, 2.0, 2.23606797749979] + + # Run Bash + bash_result = client.run_code(language="bash", code="echo 'Hello from Bash!'") + print(bash_result) +``` + +--- + +## 3. File Management + +Transfer files between your local environment and the remote sandbox. + +### Upload Files + +Use `upload_file` to send a local file to the sandbox. + +```python +with CodeInterpreterClient(name="my-interpreter") as client: + # Upload a data file for processing + client.upload_file( + local_path="./local_data.csv", + remote_path="/workspace/data.csv" + ) +``` + +### Download Files + +Use `download_file` to retrieve results generated by your scripts. + +```python +with CodeInterpreterClient(name="my-interpreter") as client: + # Download the processed report + client.download_file( + remote_path="/workspace/report.json", + local_path="./final_report.json" + ) +``` + +### Write Content Directly + +Use `write_file` to create text files on the remote sandbox without needing a local source file. + +```python +with CodeInterpreterClient(name="my-interpreter") as client: + client.write_file( + content="print('Hello World')", + remote_path="/workspace/hello.py" + ) + # Execute the file we just wrote + output = client.execute_command("python3 /workspace/hello.py") + print(output) # "Hello World" +``` + +### List Files + +Use `list_files` to list files and directories in a specified path. + +```python +with CodeInterpreterClient(name="my-interpreter") as client: + files = client.list_files("/workspace") + for f in files: + print(f"{f['name']} - {f['size']} bytes") +``` + +--- + +## 4. Best Practices: Using Context Managers + +To ensure that remote resources are terminated and local connections are closed properly, it is **strongly recommended** to use the `with` statement. + +**Complete Example:** + +```python +from agentcube import CodeInterpreterClient + +def process_data_task(): + with CodeInterpreterClient(name="my-interpreter", ttl=600) as sandbox: + print(f"Session ID: {sandbox.session_id}") + + # 1. Create a Python script remotely + script_content = """ +import json +data = {"status": "processed", "value": 42} +with open('/workspace/result.json', 'w') as f: + json.dump(data, f) +print("Data processed.") +""" + # 2. Execute the script + logs = sandbox.run_code("python", script_content) + print(f"Remote Logs: {logs}") + + # 3. Download the result + sandbox.download_file("/workspace/result.json", "./result.json") + print("File downloaded to ./result.json") + + # Session automatically stops (sandbox deleted) here + +process_data_task() +``` + +--- + +## 5. Manual Lifecycle Management + +If you cannot use a context manager (e.g., in a long-running web server), you must manually call `stop()` to free resources. + +```python +from agentcube import CodeInterpreterClient + +client = CodeInterpreterClient(name="my-interpreter", ttl=3600) + +try: + output = client.execute_command("echo 'Running long task...'") + print(output) + # ... more operations +finally: + # Critical: deletes the remote sandbox and closes connections + client.stop() +``` + +--- + +## 6. Session Reuse + +You can reuse an existing session by passing its `session_id` to a new client. This is useful for multi-step workflows where you want to preserve filesystem state across multiple scripts or processes. + +:::important +Session reuse preserves **filesystem state only**. Each `run_code` call spawns a new process, so **Python variables do NOT persist** across calls. Use files to pass state between calls. +::: + +```python +from agentcube import CodeInterpreterClient + +# Step 1: Create session and write a file +client1 = CodeInterpreterClient(name="my-interpreter") +session_id = client1.session_id +client1.write_file("42", "/workspace/value.txt") +# Do NOT call stop() — we want the session to persist + +# Step 2: Reuse the session in a new client instance +client2 = CodeInterpreterClient(name="my-interpreter", session_id=session_id) +result = client2.run_code("python", "print(open('/workspace/value.txt').read())") +print(result) # "42" + +client2.stop() # Clean up when done +``` + +--- + +## 7. Machine Learning Workflow Example + +Here is a complete example demonstrating a multi-step ML workflow using the SDK: + +```python +from agentcube import CodeInterpreterClient + +with CodeInterpreterClient(name="ml-interpreter", ttl=3600) as ci: + + # Step 1: Write requirements + ci.write_file( + content="pandas\nnumpy\nscikit-learn", + remote_path="/workspace/requirements.txt" + ) + + # Step 2: Install dependencies + ci.execute_command("pip install -r /workspace/requirements.txt") + + # Step 3: Upload training data + ci.upload_file( + local_path="./data/train.csv", + remote_path="/workspace/train.csv" + ) + + # Step 4: Train model + training_code = """ +import pandas as pd +from sklearn.linear_model import LinearRegression +import pickle + +df = pd.read_csv('/workspace/train.csv') +X, y = df[['feature1', 'feature2']], df['target'] + +model = LinearRegression().fit(X, y) +pickle.dump(model, open('/workspace/model.pkl', 'wb')) +print(f'Model R² score: {model.score(X, y):.4f}') +""" + result = ci.run_code("python", training_code) + print(result) + + # Step 5: Download the trained model + ci.download_file( + remote_path="/workspace/model.pkl", + local_path="./models/model.pkl" + ) + +print("Workflow complete! Model saved to ./models/model.pkl") +``` diff --git a/docs/agentcube/docs/developer-guide/code-interpreter-using-langchain.md b/docs/agentcube/docs/developer-guide/code-interpreter-using-langchain.md new file mode 100644 index 000000000..2cc813239 --- /dev/null +++ b/docs/agentcube/docs/developer-guide/code-interpreter-using-langchain.md @@ -0,0 +1,230 @@ +--- +sidebar_position: 8 +--- + +# Using Code Interpreter with LangChain + +You can integrate the AgentCube Code Interpreter with [LangChain](https://www.langchain.com/) and [LangGraph](https://langchain-ai.github.io/langgraph/) to build AI agents capable of executing code, solving mathematical problems, and processing data. This guide demonstrates how to wrap the `CodeInterpreterClient` as a LangChain tool and deploy it within a ReAct agent. + +## Prerequisites + +Before you begin, ensure you have the following installed: + +- **Python 3.10+** +- **LangChain & LangGraph**: `pip install langchain langchain-core langgraph` +- **AgentCube SDK**: `pip install agentcube-sdk` +- **An LLM provider SDK** (e.g., OpenAI): `pip install langchain-openai` + +You'll also need: + +- AgentCube deployed on your cluster (see [Getting Started](../getting-started.md)) +- A `CodeInterpreter` resource created in Kubernetes +- Port-forwarding set up and `WORKLOAD_MANAGER_URL`/`ROUTER_URL` environment variables set + +--- + +## Step 1: Initialize the Code Interpreter Client + +The `CodeInterpreterClient` from the `agentcube` package manages the connection to the backend execution environment. Initialize it once for the lifetime of your application. + +```python +from agentcube import CodeInterpreterClient + +# Reads WORKLOAD_MANAGER_URL and ROUTER_URL from environment (see Prerequisites) +ci_client = CodeInterpreterClient(name="my-interpreter") +``` + +--- + +## Step 2: Define the LangChain Tool + +To allow an LLM to interact with the interpreter, wrap the client execution logic in a tool using the `@tool` decorator. + +```python +from langchain_core.tools import tool +from agentcube import CodeInterpreterClient + +# Global client reference (manage lifecycle at the application level) +ci_client: CodeInterpreterClient | None = None + +@tool +def run_python_code(code: str) -> str: + """ + Executes Python code in a sandboxed environment and returns the output. + Use this tool to perform calculations, data analysis, or script execution. + Always write complete, runnable Python scripts. + """ + global ci_client + try: + if ci_client is None: + # Reads WORKLOAD_MANAGER_URL and ROUTER_URL from environment (see Prerequisites) + ci_client = CodeInterpreterClient(name="my-interpreter") + return ci_client.run_code("python", code) + except Exception as e: + return f"Error executing code: {str(e)}" +``` + +--- + +## Step 3: Create and Run the Agent + +Combine the tool with an LLM using LangGraph's prebuilt agent functions. + +```python +from langchain.chat_models import init_chat_model +from langgraph.prebuilt import create_react_agent +from langgraph.checkpoint.memory import MemorySaver +from langchain_core.messages import HumanMessage +import os + +# 1. Setup +os.environ["OPENAI_API_KEY"] = "your-api-key-here" # Use env vars or a secrets manager in production + +# 2. Initialize LLM +llm = init_chat_model("gpt-4o", model_provider="openai") + +# 3. Define Tools +tools = [run_python_code] + +# 4. Create Agent with conversational memory +memory = MemorySaver() +agent = create_react_agent(llm, tools, checkpointer=memory) + +# 5. Run the Agent +config = {"configurable": {"thread_id": "math-session-1"}} +query = "Calculate the 10th Fibonacci number using Python." + +print(f"User: {query}") +result = agent.invoke( + {"messages": [HumanMessage(content=query)]}, + config=config +) +print(f"Agent: {result['messages'][-1].content}") +``` + +**Example output:** + +``` +User: Calculate the 10th Fibonacci number using Python. +Agent: The 10th Fibonacci number is **55**. Here's the Python code that was used: + +def fib(n): + a, b = 0, 1 + for _ in range(n): + a, b = b, a + b + return a + +print(fib(10)) # Output: 55 +``` + +--- + +## Full Example: Math Agent Service (FastAPI) + +The following example demonstrates how to host the agent as a production-grade service using FastAPI. It manages the `CodeInterpreterClient` lifecycle using application lifespan events. + +```python +from fastapi import FastAPI, Request +from contextlib import asynccontextmanager +from langchain.chat_models import init_chat_model +from langchain_core.tools import tool +from langgraph.prebuilt import create_react_agent +from langgraph.checkpoint.memory import MemorySaver +from agentcube import CodeInterpreterClient +import uvicorn +import os + +# --- Global State --- +ci_client: CodeInterpreterClient | None = None + +@tool +def run_python_code(code: str) -> str: + """Executes Python code in an isolated sandbox and returns the output.""" + global ci_client + if ci_client: + return ci_client.run_code("python", code) + return "Code Interpreter is not initialized." + +# --- Application Lifespan --- +@asynccontextmanager +async def lifespan(app: FastAPI): + # Startup: Initialize the Code Interpreter session + global ci_client + print("Initializing Code Interpreter session...") + # Reads WORKLOAD_MANAGER_URL and ROUTER_URL from environment (see Prerequisites) + ci_client = CodeInterpreterClient(name="my-interpreter", ttl=86400) + yield + # Shutdown: Properly clean up the session + if ci_client: + print("Stopping Code Interpreter session...") + ci_client.stop() + +# --- App Setup --- +app = FastAPI(title="AgentCube Math Agent", lifespan=lifespan) + +llm = init_chat_model("gpt-4o", model_provider="openai") +memory = MemorySaver() +agent = create_react_agent(llm, [run_python_code], checkpointer=memory) + +# --- API Endpoint --- +@app.post("/chat") +async def chat_endpoint(request: Request): + data = await request.json() + query = data.get("query") + thread_id = data.get("thread_id", "default") + + config = {"configurable": {"thread_id": thread_id}} + + result = await agent.ainvoke( + {"messages": [("user", query)]}, + config=config + ) + + return { + "response": result["messages"][-1].content, + "thread_id": thread_id + } + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8000) +``` + +**Usage:** + +```bash +# Start the service +python app.py + +# Query the agent +curl -X POST http://localhost:8000/chat \ + -H "Content-Type: application/json" \ + -d '{"query": "What is 2^32?", "thread_id": "session-1"}' +``` + +--- + +## Best Practices + +### Client Lifecycle Management + +- **Initialize once** at application startup, not per-request. Creating a new session on every request is expensive. +- **Clean up on shutdown** using `client.stop()` or `lifespan` context managers. +- **Handle exceptions** in your tool function — the LLM can recover from tool errors if you return a descriptive error string. + +### Security + +- **Never hardcode API keys** in source code. Use environment variables or a secrets manager. +- The AgentCube sandbox isolates code execution — the LLM cannot access your host filesystem or other system resources. +- Consider setting resource limits in your `CodeInterpreter` CRD to prevent runaway code from consuming excessive cluster resources. + +### Conversational Memory + +The `MemorySaver` in these examples stores conversation history **in-memory**. For production applications, use a persistent checkpointer (e.g., `PostgresSaver` or `RedisSaver` from LangGraph) to survive service restarts. + +--- + +## Next Steps + +- [Python SDK Guide](./code-interpreter-python-sdk.md) — Detailed reference for all SDK methods +- [API Reference](../api-reference.md) — Low-level REST API documentation +- [PCAP Analyzer Tutorial](../tutorials/pcap-analyzer.md) — A real-world example using AgentCube diff --git a/docs/agentcube/docs/developer-guide/contributing.md b/docs/agentcube/docs/developer-guide/contributing.md new file mode 100644 index 000000000..093b7502d --- /dev/null +++ b/docs/agentcube/docs/developer-guide/contributing.md @@ -0,0 +1,231 @@ +--- +sidebar_position: 6 +--- + +# Contributing Guide + +Thank you for your interest in improving AgentCube! This guide outlines how to get started, the workflow we follow, and the expectations for contributors. The structure closely follows the [Volcano](https://github.com/volcano-sh/volcano/blob/master/contribute.md) contributor guide, with adjustments for the AgentCube project. + +## How to Get Involved + +- Join the conversation on GitHub: + - [Issues](https://github.com/volcano-sh/agentcube/issues) for bug reports and feature requests + - [Discussions](https://github.com/volcano-sh/agentcube/discussions) for design questions and ideas +- Review the [Code of Conduct](https://github.com/volcano-sh/community/blob/master/CODE_OF_CONDUCT.md) before participating + +--- + +## Contribution Workflow + +### 1. Pick or Propose Work + +- Search open issues labeled `good first issue` or `help wanted` +- If you have a new idea, open an issue describing the motivation, proposal, and alternatives +- For large changes, propose an enhancement in Discussions first to get feedback + +### 2. Set Up Your Environment + +Install the required tools: + +```bash +# Required +go version # Must be the version in go.mod +make --version +docker --version # or podman + +# Recommended for local testing +kind version # Kubernetes in Docker +kubectl version --client +``` + +Clone the repository: + +```bash +git clone https://github.com/volcano-sh/agentcube.git +cd agentcube +``` + +Verify the setup: + +```bash +make lint # Run linters +make test # Run unit tests +make build # Build binaries +``` + +### 3. Create a Working Branch + +```bash +# From the repo root +git checkout main +git pull origin main +git checkout -b feat/ +``` + +Branch naming conventions: + +- `feat/` — New features +- `fix/` — Bug fixes +- `docs/` — Documentation changes +- `refactor/` — Refactoring + +### 4. Develop with Tests + +- Follow Go best practices and respect existing module structure under `pkg/` and `cmd/` +- Maintain backwards compatibility for user-facing APIs (CRDs, CLI, HTTP schemas) +- Add unit tests in the relevant `*_test.go` files or integration tests under `test/` +- Run `make lint` and `make test` before submitting your changes + +```bash +# Run a specific package's tests +go test -v ./pkg/workloadmanager/... + +# Run with race detector +go test -race ./... + +# Check test coverage +go test -coverprofile=coverage.out ./... +go tool cover -html=coverage.out +``` + +### 5. Commit Conventions + +Use clear, descriptive commit messages in the format `component: summary`: + +``` +router: fix session ID not returned in response header +workloadmanager: add garbage collection for expired sandboxes +docs: update getting-started with Redis setup steps +``` + +- Reference issues with `Fixes #` or `Refs #` when applicable +- Sign off your commits if required by your employer/company policies + +```bash +git commit -m "router: fix nil pointer when session not found + +Fixes #123" +``` + +### 6. Keep Your Branch Up to Date + +Rebase frequently on `main` to reduce merge conflicts: + +```bash +git fetch origin +git rebase origin/main +``` + +Resolve conflicts locally and rerun tests after rebasing. + +### 7. Open a Pull Request + +- Push your branch and create a PR against `main` +- Fill in the PR template, covering: + - Problem statement + - Summary of changes + - Testing performed + - Screenshots/logs if relevant +- Link related issues or discussions for context +- Request review from maintainers or area owners (see the `OWNERS` directories) + +### 8. Code Review + +To make it easier for your PR to receive reviews, consider that reviewers will need you to: + +- Follow [good coding guidelines](https://go.dev/wiki/CodeReviewComments) +- Write [good commit messages](https://chris.beams.io/posts/git-commit/) +- Break large changes into a logical series of smaller patches which individually make easily understandable changes, and in aggregate solve a broader issue +- Label PRs with appropriate reviewers: read the messages the bot sends you to guide you through the PR process + +### 9. Address Review Feedback + +- Be responsive to comments and iterate quickly +- Reply to each comment once addressed +- Squash commits if asked by reviewers to keep history clean + +### 10. Celebrate the Merge 🎉 + +Once the PR is approved and checks are green, the maintainer will merge it. Your contribution becomes part of the AgentCube history! + +--- + +## Coding Standards + +- **Go formatting**: Run `make fmt` to automatically format code with `gofmt` +- **Logging**: Maintain consistent log semantics via shared logging packages under `pkg/` +- **API compatibility**: Keep public API changes backward compatible; update CRDs and generated clients when fields change (`make generate`) +- **Documentation**: Document new features under `docs/` and update READMEs/examples when behavior changes + +--- + +## Testing Guidelines + +- Unit tests are mandatory for new functionality and bug fixes +- Use table-driven tests where appropriate for clarity +- For concurrency-sensitive code, add race detector checks (`go test -race ./...`) +- Integration tests should target scenarios under `test/` or `example/` + +See the [Testing Guide](./testing.md) for detailed instructions. + +--- + +## Documentation Expectations + +- Update relevant docs under `docs/` +- Provide getting-started examples if introducing new CRDs or CLI commands +- Refresh charts/examples under `example/` when changing deployments +- Include release notes summary for significant changes (tag `release-note`) in PRs + +--- + +## Tooling Reference + +| Command | Description | +| -------------------------- | ---------------------------------------- | +| `make lint` | Runs `golangci-lint` | +| `make test` | Runs all unit tests | +| `make e2e` | Runs the full E2E test suite | +| `make build` | Builds the Workload Manager binary | +| `make build-agentd` | Builds the AgentD binary | +| `make build-router` | Builds the Router binary | +| `make build-all` | Builds all component binaries to `bin/` | +| `make docker-build` | Builds the Workload Manager Docker image | +| `make docker-build-router` | Builds the Router Docker image | +| `make docker-build-picod` | Builds the PicoD Docker image | +| `make generate` | Regenerates CRDs and DeepCopy methods | +| `make gen-client` | Regenerates client-go code | +| `make gen-all` | Regenerates all codegen artifacts | +| `make fmt` | Formats Go code with `gofmt` | + +--- + +## Governance and Ownership + +- Maintainers are listed in the top-level [`OWNERS`](https://github.com/volcano-sh/agentcube/blob/main/OWNERS) file and `OWNERS` files in subdirectories +- Subsystem owners review and approve changes in their areas +- Major design decisions go through design docs in `docs/design/` + +--- + +## AI Guidance + +Using AI tools to help write your PR is acceptable, but as the author, you are responsible for understanding every change. Do not leave the first review of AI-generated changes to the reviewers — verify the changes (code review, testing, etc.) before submitting your PR. + +Reviewers may ask questions about your AI-assisted code, and if you cannot explain why a change was made, the PR will be closed. When responding to review comments, please do so without relying on AI tools. If you used AI tools in preparing your PR, please disclose this in the "Special notes for your reviewer" section. + +--- + +## Security Reporting + +For sensitive security issues, email `volcano-security@googlegroups.com` **instead of** filing a public GitHub issue. Provide: + +- Steps to reproduce +- Affected components and versions +- Impact assessment + +--- + +## License + +By contributing, you agree that your contributions will be licensed under the Apache 2.0 License. See [LICENSE](https://github.com/volcano-sh/agentcube/blob/main/LICENSE) for details. diff --git a/docs/agentcube/docs/developer-guide/intro.md b/docs/agentcube/docs/developer-guide/intro.md index 992c28ed1..a3dc143b8 100644 --- a/docs/agentcube/docs/developer-guide/intro.md +++ b/docs/agentcube/docs/developer-guide/intro.md @@ -1,3 +1,7 @@ +--- +sidebar_position: 1 +--- + # Developer Guide Welcome to the AgentCube Developer Guide! This section is for developers who want to contribute to the AgentCube project, build custom agent runtimes, or integrate deeply with the AgentCube control plane. @@ -8,6 +12,14 @@ Welcome to the AgentCube Developer Guide! This section is for developers who wan - **[Building Agent Runtimes](./building-runtimes.md)**: Instructions for creating custom container images that work with AgentCube's sandbox environment. - **[Project Structure](./project-structure.md)**: An overview of the codebase and where things are located. - **[Testing](./testing.md)**: How to run unit and end-to-end tests. +- **[Contributing](./contributing.md)**: Contribution workflow, coding standards, and governance. + +## SDK & Integration Guides + +If you're building applications on top of AgentCube rather than contributing to it: + +- **[Python SDK Guide](./code-interpreter-python-sdk.md)**: Detailed reference for the `agentcube` Python SDK — executing code, managing files, session lifecycle, and best practices. +- **[LangChain Integration](./code-interpreter-using-langchain.md)**: How to wrap the AgentCube Code Interpreter as a LangChain tool and deploy a ReAct agent. ## Community & Contributing @@ -21,3 +33,4 @@ Please read and follow our **[Code of Conduct](https://github.com/volcano-sh/age - Join the **[Volcano Community](https://volcano.sh/en/docs/community/)** discussions. - File issues or pull requests on our **[GitHub Repository](https://github.com/volcano-sh/agentcube)**. +- Search for issues labeled `good first issue` or `help wanted` to find a starting point. diff --git a/docs/agentcube/docs/faq.md b/docs/agentcube/docs/faq.md new file mode 100644 index 000000000..8b0545b76 --- /dev/null +++ b/docs/agentcube/docs/faq.md @@ -0,0 +1,207 @@ +--- +sidebar_position: 7 +--- + +# FAQ + +Answers to the questions that come up most often. + +--- + +## General + +### What is AgentCube? + +AgentCube is a specialized subproject within the [Volcano](https://volcano.sh/) community that provides a Kubernetes-native platform for running AI Agent and code interpreter workloads. It treats agents and interpreters as first-class citizens — with dedicated scheduling, lifecycle management, and secure sandbox isolation. + +--- + +### Is AgentCube production-ready? + +AgentCube is currently in its **Proposal and Early Design phase**. It is under active development and is suitable for experimentation and pilot deployments. Specific APIs and feature sets are subject to change based on community consensus. Follow the [GitHub repository](https://github.com/volcano-sh/agentcube) for updates. + +--- + +### Do I need Volcano installed to use AgentCube? + +**No, Volcano is not strictly required.** The Volcano agent scheduler (`vc-agent-scheduler`) is an optional component, disabled by default in the Helm chart (`volcano.scheduler.enabled: false`). You can run AgentCube with standard Kubernetes scheduling. + +That said, enabling the Volcano scheduler provides advanced bin-packing, priority-based placement, and GPU-aware scheduling that significantly improves performance at scale. + +--- + +### What is the relationship between AgentCube and Volcano? + +AgentCube is a **subproject of Volcano**. It extends Volcano's strengths in managing compute-intensive batch workloads to cover the unique patterns of AI Agent workloads: interactive, stateful, intermittently active, and latency-sensitive. Volcano provides the scheduling infrastructure; AgentCube provides the agent-specific lifecycle management on top of it. + +--- + +### What languages does the AgentCube codebase use? + +- **Control plane** (Workload Manager, Router, PicoD daemon): **Go** +- **Client SDK**: **Python** +- **Website/docs**: **TypeScript** (Docusaurus) + +--- + +## Architecture + +### What's the difference between `AgentRuntime` and `CodeInterpreter`? + +| | AgentRuntime | CodeInterpreter | +| ------------------ | ----------------------------------------- | -------------------------------------------------------- | +| **Use case** | Long-running, conversational agents | Short-lived code execution sessions | +| **Security** | Standard Kubernetes Pod spec | Stricter defaults (no hostPath, restricted capabilities) | +| **Warm pool** | Not supported | Supported (`warmPoolSize`) | +| **Authentication** | Configurable | PicoD asymmetric RSA by default | +| **Typical user** | Multi-turn chat agents, tool-using agents | REPL sessions, "run this code" actions | + +Both share the same sandbox infrastructure and session lifecycle model. + +--- + +### What is PicoD? + +**PicoD** (Pico Daemon) is a lightweight RESTful HTTP daemon that runs inside every `CodeInterpreter` sandbox. It replaces traditional SSH-based access with a simpler, more secure model: + +- Exposes `/api/execute` for command/code execution. +- Exposes `/api/files` for file upload/download. +- Exposes `/health` for readiness checks. +- Uses RSA JWT-based authentication (the private key never leaves the client). + +PicoD is what the AgentCube Python SDK communicates with — you don't interact with it directly. + +--- + +### Is there a 1:1 mapping between sessions and sandboxes? + +**Yes.** AgentCube maintains a strict **1:1 mapping between a session and a sandbox**. This ensures: + +- Complete isolation — one user's code cannot access another user's data. +- Consistent context — state is preserved across multiple turns within a session. +- Clean cleanup — when a session ends, the entire sandbox (filesystem, memory, network identity) is deleted. + +--- + +### Does filesystem state persist across `run_code` calls? + +**Yes, within the same session.** Files written to the sandbox filesystem in one `run_code` call are visible in subsequent calls within the same session. + +However, **Python variables do NOT persist** between `run_code` calls, because each call spawns a new process. Use files to pass state between calls: + +```python +# Call 1: Write a result to a file +client.run_code("python", "open('/tmp/result.txt', 'w').write('42')") + +# Call 2: Read it back +result = client.run_code("python", "print(open('/tmp/result.txt').read())") +``` + +--- + +### What happens to my sandbox when I disconnect? + +The sandbox continues running until `sessionTimeout` expires (default: `15m` of inactivity). After that, it is **paused** (hibernated) to free resources. If no new traffic arrives within an additional 10 minutes, it is permanently **deleted**. + +You can configure these durations per-resource: + +```yaml +spec: + sessionTimeout: "60m" # hibernate after 1 hour idle + maxSessionDuration: "24h" # always delete after 24 hours +``` + +--- + +## Security + +### Is my code safe from other users? + +**Yes.** Each session runs in its own isolated sandbox. AgentCube's security model includes: + +1. **Process isolation**: Each sandbox is a separate Kubernetes Pod (or microVM with `runtimeClassName`). +2. **Resource limits**: CPU and memory are capped to prevent noisy-neighbor issues. +3. **Asymmetric authentication**: Requests must be signed by a private key that is only ever on the client's machine. Not even the AgentCube Router can forge your requests. +4. **Ephemeral filesystems**: By default, all sandbox data is wiped when the session ends. + +--- + +### Can I use hardware-level (microVM) isolation? + +**Yes.** Set `runtimeClassName` in the `CodeInterpreterSandboxTemplate` to use Kata Containers, Kuasar, or another microVM runtime: + +```yaml +spec: + template: + runtimeClassName: kata-qemu +``` + +This requires the corresponding RuntimeClass to be installed and configured on your Kubernetes cluster nodes. + +--- + +### What authentication modes are available? + +AgentCube supports three authentication approaches: + +| Mode | Description | Configure Via | +| ------------------------- | ----------------------------------------------------------- | ---------------------------------------- | +| **PicoD (default)** | RSA-2048 asymmetric key signing (client-side key pair) | `CodeInterpreter.spec.authMode: "picod"` | +| **External JWT/OIDC** | Validates Bearer tokens from Keycloak, Okta, Auth0, etc. | `router.jwt.*` Helm values | +| **Internal mTLS (SPIRE)** | Automatic workload identity and mTLS between all components | `spire.enabled: true` Helm value | + +These modes are complementary — you can run external JWT validation at the Router level and PicoD auth at the sandbox level simultaneously. + +--- + +## Performance + +### How fast are cold starts? + +Without a warm pool, a new session requires pulling a container image and starting a pod, which can take **5–30 seconds** depending on image size and cluster speed. + +With `warmPoolSize > 0`, an already-running pod is adopted, reducing cold-start time to **under 1 second** for the session setup. + +--- + +### How many sessions can I run concurrently? + +This is limited only by your cluster's resources. Each sandbox has configurable CPU and memory requests/limits. AgentCube's Workload Manager efficiently packs sandboxes using Volcano's bin-packing algorithm. + +--- + +### Can AgentCube scale to zero? + +**Yes.** Sandboxes are created lazily (on first request) and are automatically deleted after `sessionTimeout` + 10 minutes of inactivity. This means you only consume resources when sessions are actually active. + +--- + +## Development + +### How do I build AgentCube locally? + +See the [Local Development Guide](./developer-guide/local-development.md) for a full walkthrough. The quick version: + +```bash +git clone https://github.com/volcano-sh/agentcube.git +cd agentcube +make build-all # Builds all binaries to ./bin/ +``` + +--- + +### How do I run the tests? + +```bash +make test # Unit tests +make e2e # End-to-end tests (requires a cluster) +make lint # Linting +``` + +See the [Testing Guide](./developer-guide/testing.md) for details. + +--- + +### How do I contribute? + +See the [Contributing Guide](./developer-guide/contributing.md). We welcome all contributions — bug reports, documentation improvements, feature proposals, and code changes. diff --git a/docs/agentcube/docs/features.md b/docs/agentcube/docs/features.md new file mode 100644 index 000000000..6bf295dbd --- /dev/null +++ b/docs/agentcube/docs/features.md @@ -0,0 +1,259 @@ +--- +sidebar_position: 3 +--- + +# Features + +This page covers what AgentCube actually does under the hood — from how it keeps sandboxes warm to how it signs code execution requests. + +--- + +## 1. Extreme Low-Latency Scheduling + +Traditional Kubernetes scheduling introduces cold-start delays that are unacceptable for interactive AI Agents. AgentCube solves this with: + +### Warm Pool Management + +The `CodeInterpreter` resource supports a `warmPoolSize` field that maintains a configurable number of pre-warmed, ready-to-use sandbox Pods. When a new session is requested, an already-running Pod is adopted immediately — eliminating image-pull, container-startup, and scheduler delays. + +```yaml +apiVersion: runtime.agentcube.volcano.sh/v1alpha1 +kind: CodeInterpreter +metadata: + name: my-interpreter +spec: + warmPoolSize: 3 # Always keep 3 hot sandboxes ready + template: + image: ghcr.io/volcano-sh/picod:latest +``` + +When a warm Pod is consumed, the pool controller automatically creates a replacement to maintain the desired size. + +### Volcano Integration + +AgentCube integrates with the [Volcano](https://volcano.sh) scheduler (`vc-agent-scheduler`) for optimized AI workload placement. Volcano provides gang scheduling, priority-based placement, and bin-packing capabilities tuned for heterogeneous resources including CPUs and GPUs. + +--- + +## 2. Stateful Lifecycle Management + +AI agents are often idle for extended periods but must resume within milliseconds of the next user interaction. AgentCube implements a smart sleep/resume mechanism: + +### Sandbox State Machine + +Every sandbox transitions through a structured lifecycle: + +```mermaid +stateDiagram-v2 + [*] --> Nonexistent + Nonexistent --> Pending: first invocation + Pending --> Running: scheduled + Running --> Ready: readiness check + Ready --> Paused: idle (sessionTimeout) + Paused --> Ready: new invocation + Paused --> Deleted: no traffic (10 min) + Ready --> Deleted: maxSessionDuration reached + Paused --> Deleted: maxSessionDuration reached + Deleted --> [*] +``` + +- **Lazy creation**: Sandboxes are provisioned on the first request for a session (`Nonexistent → Pending`). +- **Hibernation**: After `sessionTimeout` (default: `15m`) of inactivity, a sandbox moves to `Paused`, freeing CPU and memory while keeping the filesystem and network identity intact. +- **Fast resume**: The next request within the pause window restores the sandbox to `Ready` immediately — the session picks up exactly where it left off. +- **Auto-cleanup**: Sandboxes are permanently deleted after 10 minutes in `Paused`, or when `maxSessionDuration` is reached. + +### Configurable Timeouts + +Both `AgentRuntime` and `CodeInterpreter` resources allow you to control the idle and maximum lifetime: + +| Field | Default | Description | +| -------------------- | ------- | ----------------------------------------------------------- | +| `sessionTimeout` | `15m` | Duration of inactivity before a sandbox is paused | +| `maxSessionDuration` | `8h` | Maximum total lifetime of a sandbox, regardless of activity | + +--- + +## 3. High-Density Resource Utilization + +AgentCube is designed to pack as many agent sessions as possible on available cluster hardware, without allowing noisy-neighbor interference. + +### Strict Resource Limits + +Every sandbox runs within CPU and Memory limits enforced at the cgroup/hardware level. You define these limits directly in the CRD template: + +```yaml +spec: + template: + resources: + limits: + cpu: "500m" + memory: "512Mi" + requests: + cpu: "100m" + memory: "128Mi" +``` + +### Isolation Levels + +AgentCube supports two isolation models: + +- **Hardened Containers**: Standard Kubernetes pods with restrictive security contexts (no root, no privilege escalation, read-only root filesystem). +- **MicroVM isolation**: Using Kubernetes RuntimeClass (e.g., Kata Containers, Kuasar) for hardware-level isolation. Configure via `runtimeClassName` in the `CodeInterpreterSandboxTemplate`. + +```yaml +spec: + template: + runtimeClassName: kata-qemu # hardware-level VM isolation +``` + +--- + +## 4. Two First-Class Workload Types + +AgentCube provides two distinct Custom Resource Definitions (CRDs) to cover different AI workload patterns: + +### AgentRuntime + +Optimized for **long-running, conversational AI agents** that: + +- Engage in multi-turn conversations. +- May need complex volume mounts or external service credentials. +- Handle diverse, custom protocol traffic on configurable port paths. + +```yaml +apiVersion: runtime.agentcube.volcano.sh/v1alpha1 +kind: AgentRuntime +metadata: + name: my-conversational-agent +spec: + targetPort: + - pathPrefix: "/" + port: 8080 + protocol: "HTTP" + podTemplate: + spec: + containers: + - name: agent + image: my-registry/my-agent:latest + sessionTimeout: "30m" + maxSessionDuration: "4h" +``` + +### CodeInterpreter + +Optimized for **short-lived, purely computational tasks** — think "Python Code Interpreter" — with: + +- Stricter security defaults (no hostPath, restricted capabilities). +- Aggressive warm-pooling for near-instant execution. +- Built-in asymmetric authentication via PicoD. + +```yaml +apiVersion: runtime.agentcube.volcano.sh/v1alpha1 +kind: CodeInterpreter +metadata: + name: my-code-runner +spec: + warmPoolSize: 2 + template: + image: ghcr.io/volcano-sh/picod:latest + sessionTimeout: "15m" + maxSessionDuration: "8h" +``` + +--- + +## 5. Secure Asymmetric Code Signing + +Security is a first-class concern. AgentCube ensures that **only the requesting client** can execute code in **their** sandbox using a split-key model: + +### How It Works + +```mermaid +sequenceDiagram + participant Client as SDK Client + participant WM as Workload Manager + participant PicoD as PicoD (in Sandbox) + + Client->>Client: Generate RSA-2048 Session Key Pair + Client->>WM: POST /v1/code-interpreters (with session public key) + WM->>WM: Generate Init JWT (signed with bootstrap private key) + WM->>PicoD: POST /init (Authorization: Bearer ) + PicoD->>PicoD: Verify JWT, store session public key (immutable) + WM-->>Client: Return session_id + endpoints + + Client->>Client: Sign request with private key → Session JWT + Client->>PicoD: POST /api/execute (Authorization: Bearer ) + PicoD->>PicoD: Verify JWT with stored session public key + PicoD-->>Client: Execution result +``` + +1. **Client-Side Key Generation**: The SDK generates a temporary RSA-2048 key pair locally. +2. **Public Key Injection**: The public key is sent to the Workload Manager, which injects it into the sandbox via a one-time `/init` call. +3. **Immutable Binding**: Once set, the public key is made immutable inside the sandbox (via `chattr +i` on Linux). No one — not even a compromised Router — can change it. +4. **Per-Request Signing**: Every API call (execute, file upload/download) is signed by the client's private key as a short-lived JWT. +5. **On-Box Verification**: PicoD validates every request signature using the stored public key. + +:::info +The **private key never leaves your client machine**. Even if the AgentCube Router or Workload Manager is compromised, an attacker cannot execute code in your running sandbox. +::: + +--- + +## 6. Command-Style API + +AgentCube exposes a synchronous, imperative API experience through the Router, giving a "command" feel rather than traditional asynchronous Kubernetes interactions. + +### Router Invocation Endpoints + +Clients interact with agents through stable, URL-addressable endpoints: + +``` +POST /v1/namespaces/{namespace}/agent-runtimes/{name}/invocations/*path +POST /v1/namespaces/{namespace}/code-interpreters/{name}/invocations/*path +``` + +- **New session**: Omit the `x-agentcube-session-id` header — a sandbox is automatically provisioned and the new session ID is returned in the response header. +- **Existing session**: Include `x-agentcube-session-id` to resume your running session. + +--- + +## 7. Pluggable Authentication + +AgentCube supports multiple authentication modes to fit your organization's security posture: + +### PicoD Authentication (Default) + +The default mode for `CodeInterpreter`, using the asymmetric RSA split-key model described above. + +### External JWT / OIDC Authentication + +The Router can validate externally issued JWT tokens from any OIDC-compliant provider (Keycloak, Okta, Auth0, Dex). Configure via Helm values: + +```yaml +router: + jwt: + issuerUrl: "http://keycloak.agentcube-system.svc:8080/realms/agentcube" + audience: "agentcube-api" + roleClaim: "realm_access.roles" + requiredRole: "sandbox:invoke" +``` + +### Internal mTLS with SPIRE + +For zero-trust deployments, AgentCube supports [SPIRE](https://spiffe.io/docs/latest/spire-about/spire-concepts/) for automatic workload identity and mTLS between all components. Enable via: + +```yaml +spire: + enabled: true + trustDomain: "cluster.local" +``` + +--- + +## 8. High Availability + +The AgentCube Router is designed as a **stateless** component. All session metadata is persisted in Redis (or Valkey), enabling: + +- Multiple Router replicas to serve traffic without coordination. +- Transparent failover if a Router pod is restarted. +- Horizontal scaling to handle high request volumes. diff --git a/docs/agentcube/docs/getting-started.md b/docs/agentcube/docs/getting-started.md index bbdc0dca1..cda174c69 100644 --- a/docs/agentcube/docs/getting-started.md +++ b/docs/agentcube/docs/getting-started.md @@ -4,100 +4,249 @@ sidebar_position: 2 # Getting Started -This guide will help you get AgentCube up and running on your Kubernetes cluster. +By the end of this guide you'll have AgentCube running on a Kubernetes cluster and a Python sandbox session executing code. ## Prerequisites -Before you begin, ensure you have the following: +Before you begin, ensure you have the following tools installed: -- A Kubernetes cluster (v1.24+) -- `kubectl` installed and configured -- [Helm](https://helm.sh/docs/intro/install/) v3 installed -- [Volcano](https://volcano.sh/en/docs/installation/) installed on your cluster (AgentCube is a Volcano subproject) +- **Kubernetes cluster**: v1.24 or later (local clusters like [Kind](https://kind.sigs.k8s.io/) or [minikube](https://minikube.sigs.k8s.io/) work well for testing) +- **kubectl**: Configured to access your cluster +- **Helm**: v3.x or later +- **Python**: 3.10 or later (for using the SDK) -## 1. Installation +## Architecture Overview -AgentCube can be installed using Helm. Follow these steps: +AgentCube consists of the following components: -### Using Helm (Recommended) +| Component | Description | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| **Workload Manager** | Control plane - manages sandbox lifecycle, session registry | +| **AgentCube Router** | Data plane - handles request routing, authentication | +| **Redis** | Session store - synchronizes state across components | +| **agent-sandbox** | Third-party controller providing Sandbox CRDs ([kubernetes-sigs/agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox)) | -Add the Volcano Helm repository (if not already added): +## Step 1: Install agent-sandbox + +AgentCube relies on the [kubernetes-sigs/agent-sandbox](https://github.com/kubernetes-sigs/agent-sandbox) project for sandbox management. Install it first: + +```bash +# Install agent-sandbox CRDs and controller +AGENT_SANDBOX_VERSION=v0.1.1 +kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/manifest.yaml +kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/extensions.yaml +``` + +Verify the installation: ```bash -helm repo add volcano-sh https://volcano-sh.github.io/volcano -helm repo update +kubectl get pods -n agent-sandbox-system ``` -Install AgentCube: +## Step 2: Deploy Redis + +AgentCube requires Redis for session state storage. Deploy Redis in your cluster: + +```bash +kubectl create namespace agentcube + +kubectl -n agentcube create deployment redis --image=redis:7-alpine --port=6379 +kubectl -n agentcube expose deployment redis --port=6379 --target-port=6379 + +# Wait for Redis to be ready +kubectl -n agentcube rollout status deployment/redis +``` + +## Step 3: Deploy AgentCube + +Clone the repository and install AgentCube using Helm: ```bash -# Clone the repository git clone https://github.com/volcano-sh/agentcube.git cd agentcube -# Install the Helm chart -helm install agentcube ./manifests/charts/base -n agentcube --create-namespace +helm install agentcube ./manifests/charts/base \ + --namespace agentcube \ + --create-namespace \ + --set redis.addr="redis.agentcube.svc.cluster.local:6379" \ + --set router.serviceAccountName="agentcube-router" ``` -### Verify Installation +:::note +Do **not** pass `--set redis.password=...` on the command line. The Redis password is injected at runtime via a Kubernetes Secret (using `secretKeyRef`). For a passwordless dev Redis, omit the flag entirely. For production, create your own Secret and reference it with `redis.secretName`. +::: -Check if the AgentCube components are running: +For production, create your own Secret and reference it: ```bash +kubectl -n agentcube create secret generic agentcube-redis \ + --from-literal=password='your-redis-password' + +helm install agentcube ./manifests/charts/base \ + --namespace agentcube \ + --create-namespace \ + --set redis.addr="redis.agentcube.svc.cluster.local:6379" \ + --set redis.secretName="agentcube-redis" \ + --set router.serviceAccountName="agentcube-router" +``` + +This will install: + +- AgentCube CRDs (`CodeInterpreter`, `AgentRuntime`) +- Workload Manager deployment +- AgentCube Router deployment + +### Configuration Options + +Key Helm values you can customize: + +| Parameter | Default | Description | +| -------------------------- | ----------- | -------------------------------------------------------------------------------- | +| `redis.addr` | `""` | Redis address (required) | +| `redis.password` | `""` | Redis password for chart-managed Secret; use `secretName` instead for production | +| `redis.secretName` | `""` | Name of a Secret with the Redis password (recommended for production) | +| `redis.secretKey` | `password` | Key in the Redis Secret | +| `router.replicas` | `1` | Router replica count | +| `router.service.type` | `ClusterIP` | Router service type | +| `workloadmanager.replicas` | `1` | Workload Manager replica count | + +For a complete list of options, see the [Configuration Guide](./configuration.md). + +### Verify Installation + +```bash +# Check all pods are running kubectl get pods -n agentcube + +# Expected output: +# NAME READY STATUS RESTARTS AGE +# agentcube-router-xxx 1/1 Running 0 1m +# workloadmanager-xxx 1/1 Running 0 1m +# redis-xxx 1/1 Running 0 2m + +# Verify CRDs are installed +kubectl get crd | grep agentcube +# Expected output: +# agentruntimes.runtime.agentcube.volcano.sh +# codeinterpreters.runtime.agentcube.volcano.sh ``` -You should see pods for `workloadmanager`, `agentcube-router`, and `volcano-agent-scheduler`. +## Step 4: Create a CodeInterpreter -## 2. Deploy Your First Agent Runtime +Create a CodeInterpreter resource that defines your sandbox template: -AgentCube uses a custom resource called `AgentRuntime` to define how your AI Agents should run. +```bash +kubectl apply -f example/code-interpreter/code-interpreter.yaml +``` -Create a file named `my-agent.yaml`: +Or create your own: ```yaml apiVersion: runtime.agentcube.volcano.sh/v1alpha1 -kind: AgentRuntime +kind: CodeInterpreter metadata: - name: sample-agent + name: my-interpreter namespace: default spec: - targetPort: + ports: - pathPrefix: "/" port: 8080 protocol: "HTTP" - podTemplate: - spec: - containers: - - name: agent - image: python:3.11-slim - command: ["python3", "-m", "http.server", "8080"] + template: + image: ghcr.io/volcano-sh/picod:latest + args: + - --workspace=/root + resources: + limits: + cpu: "500m" + memory: "512Mi" + requests: + cpu: "100m" + memory: "128Mi" sessionTimeout: "15m" - maxSessionDuration: "1h" + maxSessionDuration: "8h" +``` + +Verify the CodeInterpreter is created: + +```bash +kubectl get codeinterpreter ``` -Apply the manifest: +## Step 5: Use the Python SDK + +### Install the SDK ```bash -kubectl apply -f my-agent.yaml +pip install agentcube-sdk ``` -## 3. Access Your Agent +### Set Up Access -Once the `AgentRuntime` is created, you can access it through the AgentCube Router. +To access the services from your local machine, use port-forwarding. -The Router provides a stable entry point for your agents and handles dynamic scaling and lifecycle management (like sleep/resume). +Open **two separate terminals** and run: -Find the Router's address: +```bash +# Terminal 1: Forward the Workload Manager +kubectl port-forward -n agentcube svc/workloadmanager 8080:8080 +``` ```bash -kubectl get svc -n agentcube agentcube-router +# Terminal 2: Forward the Router +kubectl port-forward -n agentcube svc/agentcube-router 8081:8080 +``` + +Then, in a **third terminal**, set your environment variables: + +```bash +export WORKLOAD_MANAGER_URL="http://localhost:8080" +export ROUTER_URL="http://localhost:8081" +``` + +### Run Your First Code + +Create a file called `quickstart.py` with the following content: + +```python +from agentcube import CodeInterpreterClient + +with CodeInterpreterClient(name="my-interpreter") as client: + result = client.run_code("python", "print('Hello from AgentCube!')") + print(result) ``` -You can now send requests to your agent via the router! +This script connects to the CodeInterpreter you created in Step 4, launches an isolated sandbox session, sends a Python snippet to be executed inside it, and prints the output. + +Run it: + +```bash +python quickstart.py +``` + +Expected output: + +``` +Hello from AgentCube! +``` + +For detailed SDK usage, see the [Python SDK Guide](./developer-guide/code-interpreter-python-sdk.md). ## Next Steps -- Explore the [PCAP Analyzer Example](https://github.com/volcano-sh/agentcube/tree/main/example/pcap-analyzer) for a real-world use case. -- For more details on the architecture, see the **[Architecture Overview](./architecture/overview.md)** or the original **[Design Proposal](https://github.com/volcano-sh/agentcube/blob/main/docs/design/agentcube-proposal.md)**. -- Check out the [Python SDK](https://github.com/volcano-sh/agentcube/tree/main/sdk-python) to build your own agents. +- [Python SDK Guide](./developer-guide/code-interpreter-python-sdk.md) - Detailed SDK documentation +- [LangChain Integration](./developer-guide/code-interpreter-using-langchain.md) - Integration guide +- [Architecture Overview](./architecture/overview.md) - Architecture details +- [Configuration Reference](./configuration.md) - All configuration options + +## Cleanup + +To remove AgentCube from your cluster: + +```bash +helm uninstall agentcube -n agentcube +kubectl delete namespace agentcube +AGENT_SANDBOX_VERSION=v0.1.1 +kubectl delete -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/extensions.yaml +kubectl delete -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/manifest.yaml +``` diff --git a/docs/agentcube/docs/troubleshooting.md b/docs/agentcube/docs/troubleshooting.md new file mode 100644 index 000000000..2d61e2122 --- /dev/null +++ b/docs/agentcube/docs/troubleshooting.md @@ -0,0 +1,297 @@ +--- +sidebar_position: 6 +--- + +# Troubleshooting + +Common problems and how to fix them. If something is broken, start here. + +--- + +## Installation Issues + +### Pods are stuck in `Pending` state + +**Symptom:** `kubectl get pods -n agentcube` shows Workload Manager or Router pods with status `Pending`. + +**Diagnose:** + +```bash +kubectl describe pod -n agentcube +``` + +**Common causes and solutions:** + +| Cause | Solution | +| ------------------------------------------- | -------------------------------------------------------------------------------------- | +| Insufficient cluster resources (CPU/memory) | Scale up your cluster or reduce resource requests in Helm values | +| Missing `agent-sandbox` CRDs | Run `kubectl get crd \| grep sandbox` to confirm. Re-install agent-sandbox if missing. | +| Image pull error (private registry) | Set `imagePullSecrets` in Helm values or ensure the cluster has access to `ghcr.io` | + +--- + +### `kubectl get crd | grep agentcube` returns nothing + +**Cause:** The Helm chart installation failed silently, or the CRDs were not applied. + +**Solution:** + +```bash +# Check Helm release status +helm status agentcube -n agentcube + +# Manually apply CRDs +kubectl apply -f manifests/crd/ +``` + +--- + +### Helm install fails with Redis error + +**Symptom:** Helm install fails with an error like `redis: connection refused`. + +**Cause:** The Redis deployment isn't running before AgentCube is installed, or the address is wrong. + +**Solution:** + +```bash +# Check Redis is running +kubectl get pods -n agentcube | grep redis + +# Wait for Redis to be ready, then install AgentCube +kubectl -n agentcube rollout status deployment/redis +``` + +Verify you've set the correct Redis address in `redis.addr`: + +```bash +helm install agentcube ./manifests/charts/base \ + --set redis.addr="redis.agentcube.svc.cluster.local:6379" +``` + +--- + +## Session and Sandbox Issues + +### Session creation fails: `Bad Request` from Router + +**Symptom:** The Router returns a `400 Bad Request` when attempting a new invocation. + +**Diagnose:** + +```bash +kubectl logs -n agentcube deployment/agentcube-router +kubectl logs -n agentcube deployment/workloadmanager +``` + +**Common causes:** + +- The `AgentRuntime` or `CodeInterpreter` resource does not exist in the specified namespace. +- The resource name in the URL does not match. +- The `agent-sandbox` CRDs or controller are not running. + +```bash +# Verify the resource exists +kubectl get agentruntime my-agent -n default +kubectl get codeinterpreter my-interpreter -n default +``` + +--- + +### Sessions expire unexpectedly + +**Symptom:** Sessions time out faster than expected. + +**Cause:** Default `sessionTimeout` is `15m`. If your agent is idle for 15 minutes, the sandbox is paused. After another 10 minutes of being paused, it is permanently deleted. + +**Solution:** Increase the timeout in your CRD spec: + +```yaml +spec: + sessionTimeout: "60m" + maxSessionDuration: "24h" +``` + +--- + +### Cold starts are too slow (no warm pool) + +**Symptom:** New `CodeInterpreter` sessions take 30+ seconds to become ready. + +**Solution:** Enable warm pooling: + +```yaml +spec: + warmPoolSize: 3 # Keep 3 pre-warmed sandboxes +``` + +After updating, verify the warm pool pods are running: + +```bash +kubectl get pods -n default -l agentcube.volcano.sh/warmpool=true +``` + +--- + +## Authentication Issues + +### `401 Unauthorized` from PicoD + +**Symptom:** Requests to `/api/execute` or `/api/files` return `401 Unauthorized`. + +**Common causes:** + +1. **Session JWT is expired**: JWTs are short-lived. The SDK should auto-renew them, but if you're making raw HTTP calls, ensure `exp` is in the future. + +2. **Wrong private key**: The JWT must be signed by the private key whose corresponding public key was injected during `/init`. If you've created a new SDK client for an existing session, it won't have the original private key. + +3. **Sandbox not initialized**: If you bypassed the Workload Manager and called PicoD directly without `/init`, it will reject all requests. + +**Debug:** + +```bash +# Decode a JWT to inspect claims (don't send private keys to external services) +echo "" | cut -d. -f2 | base64 -d 2>/dev/null | python3 -m json.tool +``` + +--- + +### External JWT validation fails (`router.jwt` is configured) + +**Symptom:** Router returns `401 Unauthorized` even with a valid token. + +**Diagnose:** + +```bash +kubectl logs -n agentcube deployment/agentcube-router | grep jwt +``` + +**Checklist:** + +- Is `router.jwt.issuerUrl` pointing to the correct OIDC discovery URL? +- Does the token's `aud` claim match `router.jwt.audience`? +- Does the user have the role specified in `router.jwt.requiredRole`? +- Is the OIDC provider reachable from within the cluster? + +```bash +# Test OIDC discovery from inside the cluster +kubectl -n agentcube exec deployment/agentcube-router -- \ + curl -s /.well-known/openid-configuration | python3 -m json.tool +``` + +--- + +## Python SDK Issues + +### `ConnectionRefusedError` when running the SDK + +**Symptom:** The Python SDK raises `ConnectionRefusedError` on the first call. + +**Cause:** The Workload Manager or Router isn't accessible from your local machine. + +**Solution:** Set up port-forwarding in separate terminal windows: + +```bash +# Terminal 1 +kubectl port-forward -n agentcube svc/workloadmanager 8080:8080 + +# Terminal 2 +kubectl port-forward -n agentcube svc/agentcube-router 8081:8080 +``` + +Then set environment variables: + +```bash +export WORKLOAD_MANAGER_URL="http://localhost:8080" +export ROUTER_URL="http://localhost:8081" +``` + +--- + +### `WORKLOAD_MANAGER_URL` not set error + +**Symptom:** SDK raises `ValueError: WORKLOAD_MANAGER_URL is not set`. + +**Solution:** Set the environment variable or pass the URL directly: + +```python +from agentcube import CodeInterpreterClient + +client = CodeInterpreterClient( + workload_manager_url="http://localhost:8080", + router_url="http://localhost:8081" +) +``` + +--- + +### Code execution times out + +**Symptom:** `run_code()` raises a `TimeoutError`. + +**Cause:** The default execution timeout is 30 seconds. Long-running computations will exceed this. + +**Solution:** Pass a longer timeout: + +```python +result = client.run_code("python", long_script, timeout=300) # 5 minutes +``` + +--- + +## SPIRE / mTLS Issues + +### SPIRE agent `CrashLoopBackOff` + +**Symptom:** `kubectl get pods -n agentcube | grep spire` shows SPIRE agent pods crashing. + +**Cause:** For local development clusters (Kind/Minikube), the SPIRE agent cannot verify the kubelet certificate by default. + +**Solution:** + +```bash +helm upgrade agentcube ./manifests/charts/base \ + --set spire.agent.insecureBootstrap=true \ + --set spire.agent.skipKubeletVerification=true +``` + +--- + +## Diagnostic Commands + +Use these commands to quickly gather diagnostic information: + +```bash +# Overall component health +kubectl get pods -n agentcube +kubectl get pods -n agent-sandbox-system + +# Logs from all components +kubectl logs -n agentcube deployment/agentcube-router --tail=100 +kubectl logs -n agentcube deployment/workloadmanager --tail=100 + +# Check events for issues +kubectl get events -n agentcube --sort-by='.lastTimestamp' + +# Describe a specific problematic pod +kubectl describe pod -n agentcube + +# Check CRDs +kubectl get crd | grep agentcube +kubectl get agentruntime -A +kubectl get codeinterpreter -A + +# Check Redis connectivity +kubectl -n agentcube exec deployment/workloadmanager -- \ + redis-cli -h redis.agentcube.svc.cluster.local ping +``` + +--- + +## Getting Help + +If you cannot resolve an issue with the steps above: + +1. **Search existing issues**: [GitHub Issues](https://github.com/volcano-sh/agentcube/issues) +2. **Open a new issue**: Include the output of diagnostic commands above, your Helm values, and a description of the expected vs. actual behavior. +3. **Security vulnerabilities**: Email `volcano-security@googlegroups.com` instead of filing a public issue.