aisw serve 启动 PocketBase 后端,并挂载自定义 /api/aisw/* 路由与嵌入式 Web UI。
http://127.0.0.1:8090
默认仅监听本机。Web UI 入口:GET /
GET /api/aisw/config-preview?agent=claude&provider=glm&model=glm-5.3Projects agent + provider + model through the real launch pipeline (dry-run) and returns the exact config files and env vars the session would use — no process starts. Files carry a name key that maps onto the agent-config whitelist for one-click persistence.
GET /api/aisw/agent-configsReturns the whitelisted local config files of claude code (~/.claude/settings.json), codex (~/.codex/config.toml, ~/.codex/auth.json) and opencode (~/.config/opencode/opencode.json) with their current content.
PUT /api/aisw/agent-configs/{agent}/{name}Body: {"content": "<full file text>"} — atomically saves to the whitelisted path (0600, parent dirs created). Paths outside the whitelist are rejected. Note auth.json contains API keys; the endpoint is meant for the local Web UI.
GET /api/aisw/terminal
Connection: Upgrade
Upgrade: websocketUpgrades to a WebSocket bridged to a local PTY shell ($SHELL -l). Wire protocol:
- client → server text frames: keystrokes; JSON control frames
{"type":"resize","cols":N,"rows":N} - client → server binary frames: raw stdin
- server → client binary frames: raw PTY output
- server → client text frame
{"type":"exit"}: the shell exited
Each connection is an independent session; closing the socket terminates the shell. The endpoint grants local shell access — keep the server bound to 127.0.0.1 unless you trust the network.
自定义 /api/aisw/* 端点无认证,面向本地开发使用(默认 127.0.0.1)。请勿将未鉴权的 serve 暴露到公网。
PocketBase 集合端点为公开只读;匿名 create/update/delete 未启用。
| 端点 | api_key 行为 |
|---|---|
GET /api/aisw/catalog |
清空为空字符串 |
GET/POST/PUT /api/aisw/providers* |
掩码:前4位****后4位(空 key 返回空) |
PUT /api/aisw/providers/{slug} |
请求体 api_key 为空时保留数据库中已有 key |
GET /api/collections/providers/records |
PocketBase hidden field,不返回 |
GET /
GET /style.css
GET /app.js嵌入式静态页面(internal/webui/static/),通过 /api/aisw/* 完成 Provider/Profile 管理与预设导入。
GET /api/aisw/healthResponse:
{
"ok": true,
"service": "innate-aiswitcher"
}GET /api/aisw/catalog返回 agents 与 providers(api_key 已清空)。
GET /api/aisw/agents返回全部已 seed 的 agent 记录(只读)。
GET /api/aisw/presets返回内置 provider-presets.toml 中的预设列表(与 aisw provider presets 同源)。
GET /api/aisw/providersGET /api/aisw/providers/{slug}POST /api/aisw/providers
Content-Type: application/jsonBody: Provider JSON(slug, name, base_url, api_key, api_protocol, default_model, headers, endpoints, capabilities, notes, active)
Response: 201 Created,api_key 已掩码。
PUT /api/aisw/providers/{slug}
Content-Type: application/json路径 {slug} 与 body 中的 slug 应对齐。api_key 留空则保留原值。
DELETE /api/aisw/providers/{slug}Response:
{ "ok": true }POST /api/aisw/providers/from-preset
Content-Type: application/jsonBody:
{
"preset_slug": "glm",
"api_key": "sk-..."
}根据内置厂商预设生成 vendor provider 并 upsert(与 TUI/CLI 预设投影规则一致):一把 API key + 按协议划分的 variants + 预设 models 列表,claude/codex/opencode 均可直接使用。
POST /api/aisw/presetsBody: {"slug": "volcengine-claude"} — derives a preset from the stored provider (API key excluded) and writes it to the user presets directory (~/.innate-aiswitcher/presets/<slug>.toml).
POST /api/aisw/presets/importBody: {"content": "<preset TOML text>"} — parses [[presets]] blocks and saves each as a user preset file.
DELETE /api/aisw/presets/{slug}Deletes a user-saved preset file; builtin presets are rejected. GET /api/aisw/presets returns builtin and user presets with a source field (builtin | user); user presets override builtin entries of the same slug.
GET /api/aisw/providers/{slug}/models与 aisw test models {slug} 相同(调用远端 models 端点)。此外可用 POST /api/aisw/providers/{slug}/models(body {"model":"...","default":false})向已配置模型列表添加模型、DELETE /api/aisw/providers/{slug}/models/{model} 移除模型 —— 模型共享 Provider 已保存的 API key。
Response:
{
"ok": true,
"status_code": 200,
"endpoint": "https://api.example.com/v1/models",
"models": ["model-a", "model-b"],
"message": ""
}连通失败时 HTTP 状态码为 502。
POST /api/aisw/providers/{slug}/test
Content-Type: application/json与 aisw test provider {slug} 相同。
Body:
{
"model": "optional-model-override"
}Response:
{
"ok": true,
"status_code": 200,
"endpoint": "https://api.example.com/v1/chat/completions",
"message": "{\"id\":\"ok\"}"
}连通失败时 HTTP 状态码为 502。
GET /api/aisw/profilesPOST /api/aisw/profiles
Content-Type: application/jsonBody: Profile JSON(slug, name, agent, provider, model, default_args, skip_permissions, is_default, config_overrides, env_overrides)
PUT /api/aisw/profiles/{slug}
Content-Type: application/jsonDELETE /api/aisw/profiles/{slug}Response:
{ "ok": true }模型市场目录功能:从 models.dev 开放目录(api.json,全量厂商/模型/价格/能力)拉取模型参考数据,按配置保存到 SQLite 和/或 JSON 文件(本地备份,接口不通时读取自动回退本地快照),并把选中模型导入厂商 Provider(共享其 API Key,可选同时设为默认模型)。
GET /api/aisw/market/settingsResponse:
{ "storage": "both", "source_url": "https://models.dev/api.json" }storage 取值:sqlite(PocketBase market_models 集合)/ file(~/.innate-aiswitcher/market/models.json,AISW_MARKET_DIR 可覆盖)/ both(默认,同时写数据库与本地备份文件)。
PUT /api/aisw/market/settingsBody: {"storage": "both"} — 非法值回落 sqlite,缺省 source_url 自动补默认值;仍指向旧 lobehub 端点的存量配置会在读取时自动迁移到 models.dev。
POST /api/aisw/market/fetch服务端一次拉取整个目录文档并写入配置的后端。Response:
{ "ok": true, "fetched": 7870, "totalCount": 7870, "categories": 222, "storages": ["sqlite", "file (~/.innate-aiswitcher/market/models.json)"], "fetchedAt": "2026-09-20T20:54:21+08:00" }GET /api/aisw/providers/{slug}/market-models返回本地快照中该 Provider 对应厂商(经 models.dev 别名映射,如 glm→zhipuai)的模型 id 列表,已配置的模型除外。供配置页模型下拉在厂商 API 不可达时离线取数。
GET /api/aisw/market/models?category=zhipu&q=glmcategory 精确匹配厂商;q 对 identifier/display_name 做包含匹配。Response:
{ "items": [{ "identifier": "glm-5.3", "displayName": "GLM 5.3", "category": "zhipu", "providers": ["zhipu", "higress"], "contextWindowTokens": 131072, "abilities": {"vision": true} }], "total": 1, "storage": "sqlite", "fetchedAt": "2026-09-09T14:00:00+08:00", "hasData": true }GET /api/aisw/market/categoriesResponse:
{ "categories": [{ "category": "zhipu", "count": 33 }], "storage": "sqlite", "fetchedAt": "2026-09-09T14:00:00+08:00", "hasData": true }POST /api/aisw/market/importBody: {"provider": "glm", "models": ["glm-5.3", "glm-air"], "default_model": "glm-5.3"}
模型加入厂商 Provider 的 models 列表(一次 upsert),自动共享该厂商已存的 API Key;default_model 可选,把其中一个导入模型提升为默认。返回脱敏后的 Provider。
跨源合并的模型排名读模型:models.dev 目录(能力/价格/上下文)+ Artificial Analysis 独立评测指数(经 OpenRouter /api/v1/models 免费转发,按 model id 关联到所有提供该模型的厂商条目)+ models.dev models.json 厂商自报 benchmark(仅展示,带来源链接,不参与排序)。快照在进程内缓存 1 小时。
GET /api/aisw/rankings?metric=coding&q=glm&limit=100Query params:
metric— 指标 id,缺省coding;取值见响应metrics目录:coding/intelligence/agentic(AA 独立评测指数,降序)、price_input/price_output($/1M,升序)、context/output_limit(token 数,降序)、released(发布日期,最新优先)。未知值返回 400。q— 对 provider/model 名称做大小写不敏感子串过滤。limit— 返回条数,缺省 100,上限 500;total始终是过滤后的总数。
Response:
{
"metrics": [{ "id": "coding", "name": "AA Coding Index", "source": "artificial_analysis", "direction": "desc", "unit": "index", "description": "…" }],
"metric": "coding",
"items": [{
"providerId": "zhipuai", "providerName": "Zhipu AI", "modelId": "glm-5.3", "name": "GLM-5.3",
"intelligence": 44.8, "coding": 74.8, "agentic": 51.2,
"inputPrice": 0.6, "outputPrice": 2.2, "context": 256000, "outputLimit": 65536,
"openWeights": true, "reasoning": true, "toolCall": true, "attachment": false,
"knowledge": "2026-07", "releaseDate": "2026-08-01",
"benchmarks": [{ "name": "SWE-Bench Pro", "score": 63.5, "metric": "resolve rate", "source": "https://…", "date": "2026-08-01" }]
}],
"total": 7870, "fetchedAt": "2026-09-20T20:00:00Z",
"sources": [{ "id": "openrouter", "name": "OpenRouter (Artificial Analysis scores)", "url": "https://…", "ok": true }]
}无对应指标值的条目沉底排序。OpenRouter 或 models.json 拉取失败时请求仍然成功(sources 里对应条目 ok=false,前端显示降级徽章);models.dev 目录本身失败返回 502。
标准 PocketBase REST,仅公开读权限:
GET /api/collections/agents/records
GET /api/collections/providers/records
GET /api/collections/profiles/recordsproviders 集合的 api_key 为 hidden field,响应中不包含。
自定义端点错误体格式:
{
"ok": false,
"message": "provider not found"
}| Status | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad request / validation error |
| 404 | Resource not found |
| 502 | Provider connectivity check failed |
| 500 | Internal server error |
PocketBase 集合端点遵循 PocketBase 标准错误格式。
| CLI Command | REST Equivalent |
|---|---|
aisw provider list |
GET /api/aisw/providers |
aisw provider add / update |
POST / PUT /api/aisw/providers/{slug} |
aisw provider delete |
DELETE /api/aisw/providers/{slug} |
aisw provider presets |
GET /api/aisw/presets |
aisw profile list |
GET /api/aisw/profiles |
aisw profile add / update |
POST / PUT /api/aisw/profiles/{slug} |
aisw test provider {slug} |
POST /api/aisw/providers/{slug}/test |
aisw test models {slug} |
GET /api/aisw/providers/{slug}/models |
| Agents catalog | GET /api/aisw/agents 或 GET /api/collections/agents/records |
| Full catalog snapshot | GET /api/aisw/catalog |