Update: 将子项目从 submodule 转为完整内容

- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用
- 添加所有子项目的完整源代码
- 保留原始 .git 为 .git.bak 备份
This commit is contained in:
freedak
2026-07-04 19:20:46 +08:00
parent 54d6465fa7
commit f7a720204a
3360 changed files with 802660 additions and 3 deletions
@@ -0,0 +1,149 @@
# Remote 能力 API · 对接示例 cookbook
> 配套 `remote-capability-api.zh.md`。所有示例用同一枚**伙伴访问令牌**(绑定到某个具体伙伴,调用即以该伙伴身份运行);端点 = WebUI/LAN 端口(默认 `25808`)或 `nomifun-web` 的服务端口。下文用 `$HOST`/`$TOKEN` 占位。
## 0. 先决:拿到端点 + 令牌
- **端点**`http://<你的实例IP>:25808`(开启 WebUI 远程访问后),或本机 `http://127.0.0.1:<port>`
- **令牌(运维侧一次性发放,绑定到一个伙伴)**:
- 桌面应用:WebUI/远程访问面板为某个伙伴点「生成访问令牌」(明文只显示一次)。
- 无头服务器:启动时 `NOMIFUN_COMPANION_TOKEN=$(openssl rand -hex 32) nomifun-web --host 127.0.0.1 --port 8787`,绑定到默认伙伴,把这串 hex 当令牌。
- 本机可信上下文(桌面 webview / dev NoAuth)可 `curl -X POST http://127.0.0.1:<port>/api/webui/companions/<companion-id>/access-token`(远程/普通 curl 会 403——铸造刻意只限本地可信)。
- 拿到后:`export TOKEN=<令牌>`;所有请求带 `Authorization: Bearer $TOKEN`
- **以伙伴身份运行**:调用继承所绑定伙伴的模型/人格/知识库;`nomi_agent_run` 不带 `model` 时用该伙伴的 profile 模型,**所以该伙伴要先配置好可用模型**(否则铸造响应里会带 `warning`)。
- **能力发现**`GET /v1/tools`(或 `/v1/tools?profile=agent` 精瘦集)列出所有工具名 + 描述 + JSON Schema;下文工具名以此为准(`nomi_agent_run` 一定有)。
---
## 1. MCP 客户端(Claude Code / Cursor / 任意 MCP Agent)—— 旗舰
最省事:把 NomiFun 作为一个 Streamable-HTTP MCP server 配进去。Claude Code / Cursor 的 `mcpServers`
```json
{
"mcpServers": {
"nomifun": {
"type": "streamable-http",
"url": "http://$HOST:25808/mcp-agent",
"headers": { "Authorization": "Bearer $TOKEN" }
}
}
}
```
- `/mcp-agent` = curated「干活」工具集(agent/browser/computer/knowledge/files);要全平台控制面用 `/mcp`
- 连上后 `tools/list` 即见 `nomi_*` 工具,`tools/call` 驱动。委派整件事就调 `nomi_agent_run`
Python 通用 MCP SDK
```python
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession
async def main():
headers = {"Authorization": "Bearer " + TOKEN}
async with streamablehttp_client("http://%s:25808/mcp" % HOST, headers=headers) as (r, w, _):
async with ClientSession(r, w) as s:
await s.initialize()
tools = await s.list_tools()
res = await s.call_tool("nomi_agent_run", {"goal": "调研 X 并写 notes.md"})
print(res)
```
---
## 2. curlHTTP/REST,最通用)
```bash
# 列能力(精瘦 agent 档)
curl -s "http://$HOST:25808/v1/tools?profile=agent" -H "Authorization: Bearer $TOKEN"
# 委派一个目标(一句话把活交给一个自治 nomi agent)
curl -s -X POST "http://$HOST:25808/v1/tools/nomi_agent_run" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"goal":"调研竞品定价并写入 notes.md","timeout_secs":600}'
# => 200 {"result":{"conversation_id":123,"status":"completed","text":"..."}}
# 长任务 => {"result":{"conversation_id":123,"status":"running",...}},之后轮询:
curl -s -X POST "http://$HOST:25808/v1/tools/nomi_agent_result" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"conversation_id":123}'
# 调任意能力(名字来自 /v1/tools)
curl -s -X POST "http://$HOST:25808/v1/tools/<tool_name>" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{...args...}'
# 危险操作:先返回 {"needs_confirmation":true,...}(HTTP 409) → 向用户复述后带 confirm 重试
curl -s -X POST "http://$HOST:25808/v1/tools/<tool>" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{...args..., "confirm": true}'
```
**结果信封**:成功 `200 {"result": <payload>}`;工具报错 `422 {"error":..}`;需确认 `409 {"needs_confirmation":true,..}`;未知工具 `404`;无/错令牌 `401`
### 流式(SSE
```bash
curl -N -X POST "http://$HOST:25808/v1/tools/nomi_agent_run/stream" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"goal":"..."}'
# 每行一个 data: JSON 事件(agent 的 text/tool_call delta),
# 末帧 data: {"type":"__result__","data":{"result":{...终值...}}}
```
---
## 3. PythonREST + SSE
```python
import requests, json
BASE = "http://%s:25808" % HOST
H = {"Authorization": "Bearer " + TOKEN, "Content-Type": "application/json"}
# 调用
r = requests.post(f"{BASE}/v1/tools/nomi_agent_run", headers=H, json={"goal": "..."})
print(r.json()) # {"result": {...}} / {"error":...} / {"needs_confirmation":...}
# 流式
with requests.post(f"{BASE}/v1/tools/nomi_agent_run/stream", headers=H,
json={"goal": "..."}, stream=True) as resp:
for line in resp.iter_lines():
if line and line.startswith(b"data: "):
ev = json.loads(line[6:])
if ev.get("type") == "__result__":
print("FINAL:", ev["data"]); break
print("delta:", ev)
```
---
## 4. nomicore CLI(人/脚本)
```bash
export NOMIFUN_URL=http://$HOST:25808
export NOMIFUN_COMPANION_TOKEN=$TOKEN
nomicore tools # 离线列出 Remote 能力(无需运行实例)
nomicore call nomi_agent_run '{"goal":"..."}'
nomicore agent "调研竞品定价并总结" # nomi_agent_run 的便捷包装
```
---
## 5. 任意 HTTP 自动化(n8n / Zapier / Make / shell 脚本)
把一个 HTTP 节点指向 `POST http://$HOST:25808/v1/tools/{name}`Header `Authorization: Bearer $TOKEN`Body = 该工具的 JSON 参数。零 SDK。
## 6. 从 OpenAPI 生成客户端
`GET http://$HOST:25808/v1/openapi.json[?profile=agent]` 是 OpenAPI 3.1 契约 —— 喂给 `openapi-generator` 生成任意语言的 typed client,或导入 Postman/Insomnia/Bruno。
## 7. 接进别的 LLM agent 框架(LangChain / OpenAI tool-calling / 自研)
`GET /v1/tools` 每个工具自带 `name` + `description` + `input_schema`(标准 JSON Schema)。把它们直接注册成你框架的工具列表;模型决定调用某工具时,转一发 `POST /v1/tools/{name}`(带 `confirm` 处理 409)。等于让 NomiFun 全平台能力即插即用地成为你 agent 的工具集。
---
## 备注
- **安全**:持令牌即全权(≈授予 RCE 等价能力);只发给可信客户端,公网前置 TLS 反代,令牌可吊销(`DELETE /api/webui/companions/{id}/access-token`,只影响对应伙伴)。
- **MCP vs REST 选择**agent/MCP 客户端用 `/mcp`(-agent);脚本/自动化/其它语言用 `/v1`;要实时进度用 `/v1/tools/{name}/stream`(SSE) 或(MCP 端长任务)`nomi_agent_run``{status:running}` 句柄 + `nomi_agent_result` 轮询。