yao/tai/docs/api.md
Max d70694b7ac ci: update Tai to 1.2.0 with new default ports and fix documentation
- Update CI (unit-test.yml, pr-test.yml) to use yaoapp/tai:1.2.0
  with new default ports (gRPC:19100, HTTP:8099, VNC:16080, Docker:12375)
- Add explicit 0.0.0.0 bind for containerized Tai instances
- Fix sandbox/v2 grpc.go default port fallback (9100 → 19100)
- Fix tai/tunnel/proxy.go fallback ports (8080→8099, 6080→16080)
- Sync tai SDK and sandbox/v2 documentation with implementation
- Add new docs: api.md, registry.md, tunnel.md

Made-with: Cursor
2026-03-08 11:33:56 +08:00

135 lines
3.8 KiB
Markdown

# Package `api`
HTTP handlers for Tai node registration, heartbeat, and unregistration. Built on [Gin](https://github.com/gin-gonic/gin), these handlers are mounted on the Yao server to allow remote Tai instances to register themselves.
## Routes
| Method | Path | Handler | Description |
|--------|------|---------|-------------|
| `POST` | `/tai-nodes/register` | `HandleRegister` | Register a Tai node |
| `POST` | `/tai-nodes/heartbeat` | `HandleHeartbeat` | Update heartbeat timestamp |
| `DELETE` | `/tai-nodes/register/:tai_id` | `HandleUnregister` | Remove a Tai node |
All endpoints require a `Bearer` token in the `Authorization` header. Tokens are validated via the Yao OAuth service.
## Authentication
```
Authorization: Bearer <access_token>
```
The token is validated against `oauth.OAuth.AuthenticateToken()`. On success, an `AuthInfo` is extracted containing `Subject`, `UserID`, `ClientID`, `Scope`, `TeamID`, and `TenantID`. The `ClientID` is used for ownership checks on heartbeat and unregister.
## Endpoints
### POST /tai-nodes/register
Registers a new Tai node in the global registry.
**Request Body:**
```json
{
"tai_id": "tai-abc123",
"machine_id": "m-001",
"version": "1.2.0",
"addr": "192.168.1.100",
"ports": {"grpc": 19100, "http": 8099, "vnc": 16080, "docker": 12375},
"capabilities": {"docker": true, "host_exec": true},
"system": {
"os": "linux",
"arch": "amd64",
"hostname": "docker-host-01",
"num_cpu": 16,
"total_mem": 34359738368
}
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `tai_id` | string | yes | Unique identifier for this Tai instance |
| `machine_id` | string | no | Host machine identifier |
| `version` | string | no | Tai version string |
| `addr` | string | no | Reachable address of the Tai server |
| `ports` | map[string]int | no | Service ports (grpc, http, vnc, docker, k8s) |
| `capabilities` | map[string]bool | no | Supported features (docker, k8s, host_exec) |
| `system` | object | no | Host system information |
**Response (200):**
```json
{
"status": "registered",
"tai_id": "tai-abc123",
"remote_ip": "203.0.113.50"
}
```
**Errors:**
| Code | Condition |
|------|-----------|
| 400 | Missing `tai_id` or invalid JSON body |
| 401 | Missing or invalid Bearer token |
| 500 | Registry not initialized |
### POST /tai-nodes/heartbeat
Updates the `LastPing` timestamp for a registered node. The node's `ClientID` must match the token's `ClientID`.
**Request Body:**
```json
{
"tai_id": "tai-abc123"
}
```
**Response (200):**
```json
{
"status": "ok"
}
```
**Errors:**
| Code | Condition |
|------|-----------|
| 400 | Missing `tai_id` or invalid JSON body |
| 401 | Missing or invalid Bearer token |
| 403 | `tai_id` belongs to a different client |
| 404 | `tai_id` not found in registry |
| 500 | Registry not initialized |
### DELETE /tai-nodes/register/:tai_id
Removes a registered node. The node's `ClientID` must match the token's `ClientID`.
**Response (200):**
```json
{
"status": "unregistered"
}
```
**Errors:**
| Code | Condition |
|------|-----------|
| 400 | Missing `tai_id` path parameter |
| 401 | Missing or invalid Bearer token |
| 403 | `tai_id` belongs to a different client |
| 404 | `tai_id` not found in registry |
| 500 | Registry not initialized |
## Node Mode
Nodes registered via this HTTP API are marked with `Mode: "direct"`. This means the Yao server can reach the Tai instance directly over the network. For tunnel-mode nodes (registered via WebSocket), see [registry.md](registry.md).
## Health Check
The registry runs a background health checker (started via `Registry.StartHealthCheck`). Direct-mode nodes that miss heartbeats beyond the configured timeout are marked `"offline"`. Nodes that remain offline longer than the cleanup threshold are automatically unregistered.