Files
autoreg-skills-max/skills/lobehub-pool/references/lobehub-cli-reverse.md

145 lines
5.1 KiB
Markdown

# LobeHub CLI Reverse Engineering (2026-07-02)
## Discovery
LobeHub has a CLI (`@lobehub/cli`, binary `lh`) that provides a REAL API to LobeHub Cloud.
This disproves the prior claim that "LobeHub = UI frontend, NOT API."
## Source
- GitHub: `lobehub/lobehub` monorepo
- CLI code: `apps/cli/src/`
- Server routers: `apps/server/src/routers/lambda/aiChat.ts` (tRPC)
- Constants: `apps/cli/src/constants/urls.ts`
## Architecture
```
lh CLI → app.lobehub.com (tRPC server)
→ agent-gateway.lobehub.com (WebSocket streaming)
→ Auth: .lobehub/credentials.json (JWT/OIDC)
```
- Server: `app.lobehub.com` (tRPC protocol)
- WebSocket gateway: `agent-gateway.lobehub.com`
- Auth headers: `X-API-Key` (API key) or `Oidc-Auth` (JWT)
- Credentials stored: `~/.lobehub/credentials.json` (encrypted blob)
- Settings: `~/.lobehub/settings.json`
## Key Commands
```bash
# Auth
lh login # Browser Device Code Flow
lh whoami # Check current user
lh login --server <url> # Custom server
# Models
lh provider list # List providers (openai, anthropic, deepseek, etc.)
lh model list <providerId> # List models for provider
lh model view <id> # Model details
# Generation
lh generate text <prompt> [options] # Text generation (single completion)
lh generate image <prompt> # Image generation
lh generate video <prompt> # Video generation
lh generate tts <text> # Text-to-speech
lh generate asr <audio-file> # Speech-to-text
# Other
lh agent # Manage agents
lh kb # Knowledge bases
lh session-group # Session groups
lh thread # Message threads
```
## `lh generate text` Options
```
-m, --model <model> Model ID (provider/model format) (default: openai/gpt-4o-mini)
-p, --provider <provider> Provider name (derived from model if omitted)
-s, --system <prompt> System prompt
--temperature <n> Temperature (0-2)
--max-tokens <n> Maximum output tokens
--stream Enable streaming (SSE, renders incrementally)
--json Output full JSON response
--pipe Pipe mode: read additional context from stdin
```
## CRITICAL: Always use `--stream --json` together
Without `--json`: plain text output (hard to parse).
Without `--stream`: `--json` tries to parse the entire response as one JSON object —
fails on models that return reasoning tokens (DeepSeek) with:
`Unexpected token 'i', "id: undefi"... is not valid JSON`
With `--stream --json`: JSON Lines output — each line is either:
1. A string token (text chunk): `"Hello"` → `json.loads()` gives the text
2. A JSON object (metadata): `{"delta":{"role":"assistant"},...}`, `{"totalTokens":...}`, `{"duration":...}`
## Stream Output Format (JSON Lines)
```
{"delta":{"role":"assistant"},"id":"gate-...","index":0} # initial delta
"token" # text chunk (string)
"another" # more text
{"totalTokens":27,"cost":0,...} # usage
{"duration":203,"latency":2585,"tps":29.55,...} # timing
```
## Status markers to filter out
These appear as string tokens but are NOT text content:
```python
SKIP_TOKENS = {"in_progress", "message_stop", "end_turn", "completed", "done", "max_tokens"}
```
## Available Models (verified 2026-07-02)
### OpenAI (via LobeHub)
- `openai/gpt-5.5` (enabled)
- `openai/gpt-5.4` (enabled)
- `openai/gpt-5.4-mini` (enabled)
- `openai/gpt-5.5-pro`, `gpt-5.4-pro`, `gpt-5.4-nano` (disabled by default)
- `openai/o4-mini`, `o3-pro`, `o3` (disabled)
### Anthropic (via LobeHub)
- `anthropic/claude-fable-5` (enabled)
- `anthropic/claude-opus-4-8` (enabled)
- `anthropic/claude-opus-4-7` (enabled)
- `anthropic/claude-sonnet-4-6` (enabled)
- `anthropic/claude-haiku-4-5` (enabled)
- `anthropic/claude-opus-4-6` (disabled)
### DeepSeek (via LobeHub)
- `deepseek/deepseek-v4-pro` (enabled)
- `deepseek/deepseek-v4-flash` (enabled)
- `deepseek/deepseek-r1` (enabled)
### Other providers available
google, glmcodingplan, kimicodingplan, moonshot, bedrock, bailiancodingplan,
vertexai, azure, azureai, aihubmix, openrouter, fal, ollama, ollamacloud, vllm
## Windows Subprocess Pitfall
`asyncio.create_subprocess_exec("lh", ...)` fails with `FileNotFoundError: [WinError 2]`.
The `lh` shim in PATH is a bash script; Windows needs `lh.cmd`.
**Fix:** Use full path to `lh.cmd`:
```python
LH_CMD = r"C:\Users\User\AppData\Roaming\npm\lh.cmd"
proc = await asyncio.create_subprocess_exec(LH_CMD, "generate", "text", ...)
```
## Python Async Generator Pitfall
`return value` inside an `async def` generator = `SyntaxError: 'return' with value in async generator`.
**Fix:** Use `yield` for final result instead of `return`:
```python
async def run_lh(...):
# ... process tokens ...
yield {"type": "done", "text": "".join(text_buf), "usage": usage}
# NO return statement
```