autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
144
skills/lobehub-pool/references/lobehub-cli-reverse.md
Normal file
144
skills/lobehub-pool/references/lobehub-cli-reverse.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user