Codync
免費、開源的 1:1 替代方案,取代 Grok Bot 與 Muse。從 iPhone、Mac 或 Linux 桌面將 Claude Code、Codex、Cursor 與 40+ 程式碼代理人作為持續機器人傳訊。群組聊天、主題串…
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Semantic router for robots and physical AI: route every action to the right policy, on the right compute, inside a safety envelope.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Every action. The right policy.
An open, programmable decision layer for robots and physical AI.
Website · SO-101 demo · Quick start · Providers & keys · Configuration · HTTP API
pip install git+https://github.com/ddiddi/solo-router
export ANTHROPIC_API_KEY=sk-ant-... # or OPENAI_API_KEY, or NEBIUS_API_KEY
solo-router run "plan how to clear the table, then wipe it"
One prompt, one command. The router picks the right model among the providers you have keys for, calls it, and falls back if it fails. On the website it is one prompt and one click: paste a key, type, press Run.
A robot does not run one model. A fold needs a VLA at 30 Hz, a hallway needs a navigation policy, "what's on the shelf?" needs a VLM, a ten-step chore needs a planner, and "stop!" needs no model at all.
Solo Router sits between your robot stack and those models. For every instruction it extracts signals, matches a decision, filters candidates against hard limits, and scores the survivors with an algorithm. The result is a model, a location (onboard, edge or cloud), a fallback chain that always ends in a fail-safe, and a trace explaining every step.
Use Solo Router when you need to:
It applies the signal → decision → algorithm architecture of vLLM Semantic Router to robotics.
| Dimension | Fragmented today | With Solo Router |
|---|---|---|
| Policies | Hard-coded model per skill | Pick the best VLA / VLM / planner per instruction |
| Compute | Onboard, edge GPU and cloud wired separately | One pool, chosen per request |
| Connectivity | Robots stall when Wi-Fi drops | Offline never routes to cloud; degraded prefers edge |
| Control loop | Slow models silently miss deadlines | Control rate → latency budget → hard filter |
| Safety | Spread across the stack | Stop preempts everything; elevated risk tightens limits |
The bundled pool is grouped by role. A task runs through all three, and each stage is routed on its own.
| Role | Onboard | Edge | Cloud | Browser (ONNX) |
|---|---|---|---|---|
| Perception · see | Florence-2-base, SmolVLM2-2.2B | Qwen2.5-VL-7B | anthropic/claude-sonnet-5-5, openai/gpt-5.5 | Florence-2-base on WebGPU / WASM |
| Reasoning · think | SmolLM2-1.7B | Qwen3-8B | anthropic/claude-sonnet-5-5, openai/gpt-5.5, nebius/gpt-oss-120b | Qwen2.5-0.5B on WebGPU / WASM |
| Action · move | ACT (SO-101), SmolVLA, nav policy | π0, GR00T N1.5, OpenVLA | — | scripted IK controller (SO-101 sim) |
| Safety · stop | safety-controller (deterministic) |
solo-router models # the pool, grouped by role
solo-router task "put the red cube in the bowl" -e so101 -o rgb,proprio --hz 30
# [perceive] scene_understanding -> qwen2.5-vl-7b @ edge (~380ms)
# [reason] long_horizon_task -> nebius/gpt-oss-120b @ cloud (~1500ms)
# [act] realtime_manipulation -> pi0-3b @ edge (~45ms)
Specific robots inherit their family's policies (so101 → arm, aloha → bimanual, unitree_g1 → humanoid, …) through embodiment_families. Action policies declare action_chunk: a chunked policy only has to answer once per chunk, so π0 at 50 steps per call fits a 30 Hz loop that a one-step policy could not.
Cloud models come from hosted providers you bring your own key for, in the spirit of OpenRouter: one OpenAI-compatible endpoint, provider/model IDs, and automatic fallback across providers.
| Provider | Key | Models | Endpoint |
|---|---|---|---|
| OpenAI | OPENAI_API_KEY | openai/gpt-5.5 | https://api.openai.com/v1 |
| Anthropic (Claude) | ANTHROPIC_API_KEY | anthropic/claude-sonnet-5-5 | https://api.anthropic.com/v1 (Messages API, translated for you) |
| Nebius Token Factory | NEBIUS_API_KEY | nebius/gpt-oss-120b (→ openai/gpt-oss-120b) | https://api.tokenfactory.nebius.com/v1 |
Keys decide routing. A provider's models are only routable when you have its key. With one key, the router uses that provider for cloud work and the robot's own models for everything else. With none, it stays self-hosted. Each rejected model shows up in the trace as no <provider> API key.
solo-router providers # which keys are set, which models they unlock
solo-router route "plan the chore, then tidy up" --providers openai # route as if you only had an OpenAI key
solo-router run "why is joint 3 overheating" # route among hosted providers and call the model
solo-router serve --proxy # OpenAI-compatible router on :8899 using your env keys
Where keys come from:
api_key_env of each provider (above).x-openai-api-key, x-anthropic-api-key or x-nebius-api-key header on any /v1/* call, so one router can serve several users with their own keys.Visitors without a key can get one free run a day. Keys can't be hidden in a static site (anything shipped to the browser is public), so the free run goes through a small Cloudflare Worker, free-tier/worker.js, that holds the keys as secrets:
RUNS_PER_DAY), counted by a salted hash of the address, never the raw IPDAILY_CAP) so a bot can't drain your creditsrouter-config.json, at most MAX_TOKENS per reply and 4,000 characters inALLOWED_ORIGINS)cd free-tier
npx wrangler login
npx wrangler kv namespace create RUNS # paste the id into wrangler.toml
npx wrangler secret put NEBIUS_API_KEY # and/or OPENAI_API_KEY, ANTHROPIC_API_KEY
npx wrangler deploy # prints https://solo-router-free.<you>.workers.dev
Then put that URL in website/index.html: <meta name="solo-free-tier" content="https://solo-router-free.<you>.workers.dev">. With the tag empty, the site has no free runs and asks for a key. Use dedicated keys with a spend limit for this.
Add a provider or a model in router.yaml. Models inherit base_url, api_format and api_key_env from their provider; upstream_model sets the provider's ID when it differs from the name:
providers:
nebius:
label: Nebius Token Factory
base_url: https://api.tokenfactory.nebius.com/v1
api_format: openai # openai | anthropic
api_key_env: NEBIUS_API_KEY
models:
- name: nebius/gpt-oss-120b
provider: nebius
upstream_model: openai/gpt-oss-120b
role: reasoning
kind: planner
location: cloud
p50_latency_ms: 1500
quality: 0.83
cost_per_1k: 0.4
Model IDs and numbers are examples. Check each provider's catalog for the models your account can use, and measure latency yourself.
browser is a fourth location. Browser models carry an onnx block (Hugging Face repo, task and per-device dtype) and the runtimes they need. The router only considers them when the request says the client can run them:
{ "instruction": "put the red cube in the bowl", "embodiment": "so101", "observations": ["rgb"],
"locations": ["browser"], "client_runtimes": ["webgpu", "wasm"] }
website/assets/onnx.js loads those models with transformers.js (ONNX Runtime Web), uses WebGPU when navigator.gpu has an adapter and WASM otherwise, and lets the browser cache the weights. Without a usable runtime, the browser models are rejected and the chain falls back as usual.
demo.html (also embedded on the homepage) runs one task, put the red cube in the bowl, on a three.js SO-101:
E-STOP routes stop to the safety controller and freezes the arm mid-motion.
With an API key (set in the playground), the reason stage calls the routed hosted planner for real, streams its plan under the stage as it is written, and the arm executes it. The demo loops, so each model is called once and its plan reused.
Run in your browser re-routes the same task with locations: ["browser"]. The router then picks Florence-2 (grounding on the rendered camera frame), Qwen2.5-0.5B (writing the plan) and the scripted IK controller. The first two run for real on your GPU. Detected boxes are ray-cast onto the table to set grasp targets, and a grasp only succeeds if a cube is actually between the jaws. The first run downloads about 850 MB of weights for WebGPU while the simulated demo keeps looping; later runs load from the browser cache. The arm, scene and the default-mode models are simulated.
pip install git+https://github.com/ddiddi/solo-router
export OPENAI_API_KEY=sk-... # any one provider key is enough
solo-router run "clean the kitchen, then load the dishwasher"
# [long_horizon_task -> openai/gpt-5.5 @ cloud]
# 1. ...
solo-router route "pick up the red cup" -e arm -o rgb,proprio --hz 20
# realtime_manipulation -> pi0-3b @ edge (~45ms)
# fallbacks: smolvla-450m -> safety-controller
solo-router route "stop!"
# emergency_stop -> safety-controller @ onboard (~2ms)
solo-router route "clean the kitchen, then load the dishwasher" --network offline
# long_horizon_task -> qwen3-8b @ edge (~900ms)
solo-router serve # dry-run server on :8899
solo-router serve --proxy # forward to the configured backends with your keys
run and route/task take the same robot flags (-e, -o, --hz, --network, --humans, --prefer, --providers). run streams the answer as it arrives and routes among hosted providers by default; add --local to include self-hosted onboard and edge endpoints.
Python 3.10+, with PyYAML as the only dependency. The server uses only the standard library, so it runs on the robot.
instruction + robot state
│
▼
┌─────────────┐ intent · horizon · safety · latency tier · modalities
│ Signals │ embodiment · network · energy · preference
└─────┬───────┘
▼
┌─────────────┐ first match by priority, e.g.
│ Decisions │ emergency_stop(1000) > realtime_manipulation(300) > navigation(290)
└─────┬───────┘ > long_horizon_task(200) > scene_understanding(150) > diagnostics(120) > conversation(0)
▼
┌─────────────┐ embodiment support · required cameras · offline → no cloud
│ Filters │ p50 latency ≤ budget · max Hz ≥ control rate · safety tier when elevated
│ │ provider key present (openai · anthropic · nebius)
└─────┬───────┘
▼
┌─────────────┐ static – first feasible
│ Algorithms │ latency_aware – highest quality that meets the deadline
└─────┬───────┘ hybrid – quality / latency / cost weights, cloud penalty on weak links
▼
model @ onboard | edge | cloud | browser + guardrails + fallbacks → safety-controller
| Signal | Source | Values |
|---|---|---|
intent | keyword lexicon | manipulation, navigation, perception, planning, diagnostics, conversation |
horizon | sequencing markers, length | short, long |
safety | stop patterns, hazard words, humans_nearby, estop | normal, elevated, critical |
latency_tier | latency_budget_ms or 1000 / control_hz | realtime (<50 ms), interactive (<500 ms), deliberative |
modalities | observations / image parts in chat | rgb, wrist_rgb, depth, proprio, lidar, … |
embodiment | request | arm, bimanual, mobile_manipulator, humanoid, quadruped, amr, drone, or a robot such as so101 |
network | request | online, degraded, offline |
energy | battery_pct | normal, low (offloads away from power-hungry onboard models) |
preference | request or decision default | balanced, quality, latency, cost |
stop, halt, emergency, e-stop, or estop: true) routes to safety-controller at priority 1000 and returns {"action": "stop", "hold_position": true}.max_speed_mps, max_force_n) and drops policies below min_safety_tier.safety-controller instead of guessing.Everything lives in one YAML file: src/solo_router/router.yaml. Copy it, edit it, and pass it with -c:
solo-router -c my-fleet.yaml serve --proxy
models:
- name: pi0-3b
kind: vla # vla | nav | vlm | llm | planner | safety
location: edge # onboard | edge | cloud | browser
p50_latency_ms: 45
max_hz: 50
quality: 0.82
embodiments: [arm, bimanual, mobile_manipulator]
requires: [rgb]
safety_tier: 2
base_url: http://edge.local:8102
decisions:
- name: realtime_manipulation
priority: 300
when: { intent: manipulation, horizon: short }
candidates: [pi0-3b, gr00t-n1.5-3b, smolvla-450m, openvla-7b]
algorithm: latency_aware
when matches any signal by value or list of values, and accepts any: / all: for composition. An empty when matches everything. A model named safety-controller is required.
Models also declare a role (perception, reasoning, action, safety). Optional fields include provider, upstream_model, action_chunk, runtimes and onnx. The pipeline block defines the stages for /v1/task: which signals each stage fixes (intent, horizon; safety can never be overridden) and whether the control-loop deadline applies.
The bundled pool is an example. Latency and quality numbers are illustrative; measure your own and replace them.
| Method | Path | Purpose |
|---|---|---|
POST | /v1/chat/completions | OpenAI-compatible. Use "model": "solo/auto" and an optional robot object |
POST | /v1/actions | Robot-native. Routes, then forwards {instruction, observation, guardrails} to the policy's /act |
POST | /v1/route | Decision only, no backend call |
POST | /v1/task | Route every pipeline stage (perceive → reason → act); headers x-solo-router-{stage} |
GET | /v1/models | solo/auto plus the configured pool, with provider and whether its key is configured |
GET | /v1/providers | Providers, their key status and the models each unlocks |
GET | /health | Liveness |
curl localhost:8899/v1/chat/completions -d @examples/chat_hand_me_scissors.json -i
# x-solo-router-decision: realtime_manipulation
# x-solo-router-model: pi0-3b
# x-solo-router-location: edge
# x-solo-router-safety: elevated
Every response includes a solo_router object (or route for /v1/actions) with signals, ranked candidates, rejected models with reasons, guardrails, fallbacks and the trace.
In dry-run mode (the default) chat returns a summary of the decision instead of calling a model. With --proxy, chat goes to the selected model (OpenAI-compatible or Anthropic Messages, translated both ways) and actions go to VLA/nav policy servers. Requests may set robot.providers to narrow the providers; in proxy mode the router only routes to providers it holds a key for.
Set "stream": true for Server-Sent Events in OpenAI's chat.completion.chunk format, from any provider. Anthropic's stream is translated, and OpenAI-compatible streams pass through. The routing headers arrive before the first token, and the last chunk before data: [DONE] carries the solo_router object. In dry-run mode the decision summary streams as one chunk.
curl -N localhost:8899/v1/chat/completions -H "x-anthropic-api-key: $ANTHROPIC_API_KEY" -d '{
"model": "solo/auto", "stream": true,
"messages": [{"role": "user", "content": "plan how to clear the table, then wipe it"}]}'
# data: {"object": "chat.completion.chunk", "model": "anthropic/claude-sonnet-5-5", "choices": [{"delta": {"content": "1. "}, ...}]}
Like OpenRouter, a failed backend falls through to the next model in the chain. The response says which model answered (x-solo-router-model, solo_router.served_by) and lists failed attempts. A stream can fall back until its first byte is sent; after that, a failure arrives as an error event. If every backend fails you get 502 with all attempts; unreachable policies return a hold action.
website/ is a static site deployed to GitHub Pages. Its playground runs website/assets/router.js, a browser port of the router, on router-config.json. Type a prompt and press Run: the router picks a model, and with a key in the API keys panel, providers.js calls OpenAI, Anthropic or Nebius Token Factory straight from your browser. The answer streams in token by token. If a provider blocks browser (CORS) requests, the answer box says so; use solo-router run instead. Robot-side picks (VLAs, edge models) are re-routed to the hosted models a browser can reach, the same way solo-router run does. After changing the YAML, regenerate it:
solo-router export > website/assets/router-config.json
tests/test_js_parity.py routes several hundred requests and task pipelines through both implementations and fails if they disagree.
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pytest -q
python -m http.server -d website 8765 # preview the site and demo