Agent 生成器
- 作者仓库星标 1
- 作者仓库 Solar
Solar Router
Purpose
Single source of truth for all AI execution in Solar:
- Provider selection and fallback live only here.
- Async routing policy (
direct_replyvsasync_draft_created) lives only here. - Used by solar-gateway (WebSocket/bridge) and solar-async-tasks (task execution).
Operational boundary
Use this skill as infrastructure for Solar runtimes and controlled diagnostics. Do not use solar-router or provider CLIs as the normal path for work that is deferred, multiprovider, browser/MCP-dependent, network/auth/keychain-dependent, long-running, or likely to block the conversation.
For that work, create or propose a task through solar-async-tasks. When solar-system supervises async-tasks, approve/queue the task and let the system runtime execute it.
Scope
- Accept JSON payload (router contract v3) on stdin; output structured JSON on stdout.
- Run the selected provider with
cwd=SOLAR_WORKSPACEso all providers seesun/,planets/, and workspaceAGENTS.md. - Resolve
SOLAR_ROUTER_SYSTEM_PROMPT_FILEandSOLAR_ROUTER_RUNTIME_DIRagainstSOLAR_WORKSPACEwhen relative. - Codex default command includes
-C <repo-root>and--add-dir ~/.codex. - Persist conversation turns in runtime dir (JSONL) for continuity.
- Implement
DecisionEngine: decidedecision.kindbased onmode,channel, and AI semantic output. - Resolve JIT context from
metadata: lookup agent/skills in planet → fallback to core → generate role inline if not found. - Write audit log (
sun/runtime/router/audit.jsonl) withstart/endevents per execution for traceability (including failed early-exit paths).
Internal architecture
scripts/
run_router.py — thin entrypoint: stdin → route() → stdout + exit
router.py — all provider-agnostic logic (parse, validate, JIT, prompt, decision engine)
providers/
__init__.py — PROVIDERS dict, exports all adapters
base.py — BaseProvider: resolve_binary, get_cmd, prepare_env, clean_output, run
claude.py — static default_cmd
codex.py — build_default_cmd() with SOLAR_WORKSPACE + CODEX_STATE_DIR
gemini.py — prepare_env (GEMINI_* vars) + clean_output (ANSI strip, OAuth guard)
agent.py — build_default_cmd() with SOLAR_WORKSPACE
Automated tests live under `core/tests/skills/solar-router/` (framework-wide layout; see `core/AGENTS.md`).
Layer contract:
router.pydecides (context, prompt, policy, response shape).providers/executes (subprocess, env, normalization). No routing logic.run_router.pydoes I/O only. No logic.
Required MCP
None
Setup
# Configure router environment variables (SOLAR_ROUTER_*, timeouts, etc.)
bash core/skills/solar-router/scripts/onboard_router_env.sh
Key environment variables:
SOLAR_ROUTER_PROVIDER_PRIORITY— Comma-separated provider list (e.g.,codex,claude,gemini,ollama)SOLAR_ROUTER_RUNTIME_DIR— Where conversation history is stored (default:sun/runtime/router)SOLAR_ROUTER_SYSTEM_PROMPT_FILE— System prompt file path (default:core/skills/solar-router/assets/system_prompt.md)SOLAR_ROUTER_CONTEXT_TURNS— Number of conversation turns to include (default:12)SOLAR_ROUTER_TIMEOUT_SEC— End-to-end router timeout, including provider execution (default:300)
Optional command overrides:
SOLAR_ROUTER_CODEX_CMDSOLAR_ROUTER_CLAUDE_CMDSOLAR_ROUTER_GEMINI_CMDSOLAR_ROUTER_OLLAMA_CMD
Ollama setup:
provider=ollamaalways targets the local model namedsolar- Build or refresh it with
bash core/skills/solar-router/scripts/setup_ollama.sh
Validation commands
# Validate skill structure
python3 core/skills/solar-skill-creator/scripts/package_skill.py core/skills/solar-router /tmp
# List configured providers (reads SOLAR_ROUTER_PROVIDER_PRIORITY)
bash core/skills/solar-router/scripts/list_providers.sh
bash core/skills/solar-router/scripts/list_providers.sh --exclude claude
bash core/skills/solar-router/scripts/list_providers.sh --exclude claude --format csv
# Diagnose router / preflight providers (native helper in this skill)
bash core/skills/solar-router/scripts/diagnose_router.sh --dry-run
bash core/skills/solar-router/scripts/diagnose_router.sh
# Full error output when a provider fails (e.g. 401, binary not found)
bash core/skills/solar-router/scripts/diagnose_router.sh --verbose
# Unit tests: router logic + provider adapters (centralized under core/tests; pytest runs unittest-style tests; no real AI calls)
uv run --project core/tests pytest core/tests/skills/solar-router -q
# Without uv: PYTHONPATH=core/skills/solar-router/scripts python3 -m unittest discover -s core/tests/skills/solar-router -p "test_*.py" -v
# Smoke tests: validate router contract v3, bridge delegation, execute_active.py JSON parsing
bash core/skills/solar-router/scripts/check_router.sh
# Live status: provider health, in-flight processes, last executions
bash core/skills/solar-router/scripts/status_router.sh
bash core/skills/solar-router/scripts/status_router.sh --last 20
Router contract v3
Input (stdin JSON)
{
"request_id": "string",
"session_id": "string",
"user_id": "string",
"text": "string",
"channel": "telegram|n8n|async-task|other",
"mode": "auto|direct_only|async_only",
"provider": "codex|claude|gemini|agent|ollama|null",
"metadata": {
"agent": "agent-name|null",
"skills": ["planet:skill-name", "core-skill-name"],
"planet": "planet-name|null"
}
}
provider: optional. If set, strict mode — no fallback. If fails →error_code: provider_locked_failed.mode: defaults toauto.direct_onlyalways returnsdirect_reply.async_onlyrequiresasync-tasksfeature enabled.channel: used byDecisionEnginefor semantic routing inmode=auto.metadata.agent: existing agent name from planet'sagents/, ornullfor JIT role generation.metadata.skills: skill name format —planet:skillresolves toplanets/<planet>/skills/<skill>/SKILL.md; unprefixedskillresolves toplanets/<metadata.planet>/skills/<skill>/SKILL.mdfirst (ifmetadata.planetis set), then falls back tocore/skills/<skill>/SKILL.md. Only description is injected (on-demand).metadata.planet: planet that owns the task domain. Used for agent/skill lookup.
Secure Invocation Protocol (Required)
To prevent JSON parsing errors (invalid control characters, unescaped newlines), always use one of these two methods when calling the router from an AI agent or shell:
Method A: Temporary JSON File (Recommended for Agents)
- Use
write_fileto create a temporary JSON file (e.g.,sun/runtime/router/request_<id>.json). - Ensure the
textfield contains explicit\nfor newlines. - Execute the router piping the file:
python3 core/skills/solar-router/scripts/run_router.py < sun/runtime/router/request_<id>.json.
Method B: Heredoc with Single Quotes (Shell)
Use a heredoc with 'EOF' (single quotes) to prevent the shell from interpreting backslashes or special characters:
cat << 'EOF' | python3 core/skills/solar-router/scripts/run_router.py
{
"request_id": "my-id",
"text": "Line 1\nLine 2",
"channel": "other",
"mode": "direct_only"
}
EOF
Critical Rules:
- Prefer escaped newlines (
\n) inside JSON strings for portability. - Escape double quotes inside the
textstring as\". - Validate JSON before sending if using a custom script.
Output (stdout JSON)
{
"status": "success|failed",
"request_id": "string",
"provider_used": "codex|claude|gemini|agent|ollama",
"reply_text": "string",
"decision": {
"kind": "direct_reply|async_draft_proposal|async_draft_created|async_activation_needed",
"task_id": "string|null",
"priority_suggested": "high|normal|low|null"
},
"error_code": "string|null",
"error": "string|null"
}
DecisionEngine rules
mode=direct_only→decision.kind=direct_replyalways.mode=async_only+async-tasksenabled →decision.kind=async_draft_created.mode=async_only+async-tasksdisabled →status=failed+ explicit error.mode=auto+channel=async-task→decision.kind=direct_reply(already in queue).mode=auto+channel=telegram|n8n|other→ AI decides semantically via structured JSON output.
Consumers
- solar-gateway:
run_websocket_bridge.pyand HTTP webhook bridge call the router with full v3 contract. - solar-async-tasks:
execute_active.py(viaexecute_active.sh) calls the router withchannel=async-task,mode=direct_only.
Runtime files
sun/runtime/router/conversations/<user_id>.jsonl— conversation history per user (for context continuity).sun/runtime/router/audit.jsonl— audit log with onestart/endrecord pair per execution. Fields:router_id(internal UUID),request_id(caller ref),user_id,metadata,provider,status,jit_generated,duration_ms.
References
references/routing-policy.md— provider priority, env keys, repo-context policy, v3 contract rules.
- 流狐分类
- 通用
- 作者声明 Agent
- 未找到明确声明;不据此推断已兼容或已测试
- 静态检查
- 88 / 100 · 启发式扫描,不代表运行安全
- 作者 / 版本 / 许可
- @Uhorizon-AI · 未声明 license
- 流狐 Token 估算
- 低消耗
- 流狐接入估算
- 需简单配置
- 是否需要外部 API Key
- 未发现要求
- 检测到的系统要求
- 未声明
- 底层运行要求
- 未声明
- 检测到的文件与系统行为
-
- 只读
- 允许写入 / 修改
- Shell 执行
- 读取环境变量
- 检测到的网络行为
- 允许外网请求
- 安装命令数
- 无(仅作为资料)
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
作者没有在当前 SKILL.md 中定义固定输出样例。 Single source of truth for all AI execution in Solar: Provider selection and fallback live only here. Async routing policy (directreply vs asyncdraftcreated) lives only here.
Use this skill as infrastructure for Solar runtimes and controlled diagnostics. Do not use solar-router or provider CLIs as the normal path for work that is deferred, multiprovider, browser/MCP-dependent, network/auth/keychain-dependent, long-running, or…
Accept JSON payload (router contract v3) on stdin; output structured JSON on stdout. Run the selected provider with cwd=SOLARWORKSPACE so all providers see sun/, planets/, and workspace AGENTS.md. Resolve SOLARROUTERSYSTEMPROMPTFILE and SOLARROUTERRUNTIMEDIR…
Layer contract: router.py decides (context, prompt, policy, response shape). providers/ executes (subprocess, env, normalization). No routing logic.
None
Key environment variables: SOLARROUTERPROVIDERPRIORITY — Comma-separated provider list (e.g., codex,claude,gemini,ollama) SOLARROUTERRUNTIMEDIR — Where conversation history is stored (default: sun/runtime/router)
# Solar Router
## Purpose
Single source of truth for all AI execution in Solar:
- **Provider selection and fallback** live only here.
- **Async routing policy** (`direct_reply` vs `async_draft_created`) lives only here.
- Used by solar-gateway (WebSocket/bridge) and solar-async-tasks (task execution).
## Operational boundary
Use this skill as infrastructure for Solar runtimes and controlled diagnostics. Do not use `solar-router` or provider CLIs as the normal path for work that is deferred, multiprovider, browser/MCP-dependent, network/auth/keychain-dependent, long-running, or likely to block the conversation.
For that work, create or propose a task through `solar-async-tasks`. When `solar-system` supervises `async-tasks`, approve/queue the task and let the system runtime execute it.
## Scope
- Accept JSON payload (router contract v3) on stdin; output structured JSON on stdout.
- Run the selected provider with `cwd=SOLAR_WORKSPACE` so all providers see `sun/`, `planets/`, and workspace `AGENTS.md`.
- Resolve `SOLAR_ROUTER_SYSTEM_PROMPT_FILE` and `SOLAR_ROUTER_RUNTIME_DIR` against `SOLAR_WORKSPACE` when relative.
- Codex default command includes `-C <repo-root>` and `--add-dir ~/.codex`.
- Persist conversation turns in runtime dir (JSONL) for continuity.
- Implement `DecisionEngine`: decide `decision.kind` based on `mode`, `channel`, and AI semantic output.
- Resolve JIT context from `metadata`: lookup agent/skills in planet → fallback to core → generate role inline if not found.
- Write audit log (`sun/runtime/router/audit.jsonl`) with `start`/`end` events per execution for traceability (including failed early-exit paths).
## Internal architecture
```
scripts/
run_router.py — thin entrypoint: stdin → route() → stdout + exit
… 作者原文负责流程事实;流狐只索引当前章节、要点、文件与命令。
章节 -> Purpose → Operational boundary → Scope → Internal architecture → Required MCP → Setup
要点 -> Provider selection and fallback · Async routing policy · Layer contract · Key environment variables · Prefer escaped newlines · Escape double quotes · Validate JSON · solar-gateway
文件/命令 -> directreply · asyncdraftcreated · solar-router · solar-async-tasks · solar-system · async-tasks · cwd=SOLARWORKSPACE · sun/
内容 SHA-256 -> 4fe0cf45ac19
方法与流程
适用与边界
原文中的明确线索
directreply、asyncdraftcreated、solar-router、solar-async-tasks、solar-system、async-tasks、cwd=SOLARWORKSPACE、sun/