HTTP 路由(http_route / static_route)

🔵 代理和全局配置可以在服务器上添加自己的 HTTP 端点,无需重新构建——采用与 script_tool / script_hook 相同的模型。两种路由:

这是对固定接口的补充,而非替代:POST /v1/inbound/:template、 POST /v1/workflows/<name>/webhook 以及 telegram/email 通道。


21.1 布局

config/
├── routes/                    # 全局路由——自动加载
│   ├── weather.yaml + weather.rhai
│   └── assets.yaml + assets/  # static_route 的静态资源文件夹
└── agents/
    └── felix/
        ├── agent.yaml         # route_files: [routes/card.yaml]
        └── routes/
            ├── card.yaml + card.rhai
            └── static/        # 代理添加的静态资源

全局路由从 config/routes/*.yaml 自动读取。 代理路由从 agent.yaml 显式挂载:

# config/agents/felix/agent.yaml   (felix — условное имя агента для примера)
route_files:
  - routes/card.yaml

代理路由注册到与全局路由同一个路由器中。按照 约定(这是警告,不是错误),代理路由的路径以 /ext/<agent>/ 开头。


21.2 http_route(脚本)

kind: http_route
name: weather                 # id маршрута (по умолчанию — имя файла); пишется в access-лог
method: GET                   # GET|POST|PUT|PATCH|DELETE|HEAD|* (по умолчанию GET)
path: /ext/weather/:city      # сегменты :param и *rest; путь должен быть уникальным
script: weather.rhai          # .rhai или .js, относительно этого YAML
auth: public                  # public | bearer | token_env | user
token_env: ""                 # env с bearer-токеном (при auth: token_env)
max_operations: 10000000      # бюджет инструкций скрипта
timeout_ms: 30000             # потолок времени на обработчик
max_body_bytes: 1048576       # лимит тела запроса (по умолчанию 1 МиБ)
# + любые свои поля → доступны в скрипте как request.config.<field>

脚本契约

fn handler(request) {
    // request = #{
    //   method: "GET",
    //   path: "/ext/weather/moscow",
    //   params: #{ city: "moscow" },      // захваты :param / *rest
    //   query: #{ unit: "c" },
    //   headers: #{ "content-type": "application/json" },
    //   body: "...",                       // сырое тело строкой ("" если нет)
    //   json: #{ ... },                    // распарсенное JSON-тело, или ()
    //   user_id: "...",                    // разрешённая идентичность, или ()
    //   user: "...",                       // канонический id пользователя, или ()
    //   config: #{ ... }                   // сырой YAML, включая свои поля
    // }
    if request.user_id == () {
        return #{ status: 401, body: #{ error: "unauthorized" } };
    }
    let r = http_get(`https://api.weather.example/${request.params.city}`);
    if r.status != 200 {
        return #{ status: 502, body: #{ error: r.error } };
    }
    #{ status: 200, body: parse_json(r.body) }
}

返回 #{ status, headers, body }(所有字段均可选):

辅助函数

与 script_tool 相同的引擎和辅助函数集:http_get/post/put/patch/delete、 http(method, …)、env_var、now、sleep_ms、urlencode/urldecode、 parse_json/to_json、json_get、extract_script_json、print/debug,以及 db_query/db_schema/db_execute 用于读写 DuckDB(见 §7.3)和 shell/exec/fs_read(见 §7.3)。

路由中 llm(...) 不可用(没有代理进程可以计入 预算)——调用会抛出错误。无法访问内核;调用之间的状态不会 保留(请使用 HTTP 或外部存储/db_*)。


21.3 static_route(文件)

kind: static_route
name: felix_assets
path: /ext/felix/*rest        # должно заканчиваться на *rest
dir: static/                  # папка относительно этого YAML
index: index.html             # отдаётся при обращении к "/" (опционально)
auth: public
cache_ttl_secs: 300           # Cache-Control (опционально)
mime:                         # переопределение content-type по расширению (опционально)
  .wasm: application/wasm

行为(仅限 GET/HEAD):

这样代理就能提供静态资源:static_route 指向其 routes/ 内的 static/ 文件夹。


21.4 认证

模式 行为
public 开放(开发环境默认)
bearer 要求 Authorization: Bearer <token> 与 auth.admin_tokens 匹配(日志中记录名称,而非值)
token_env 要求 bearer 令牌等于 token_env 中的环境变量值(未设置/为空 = 拒绝一切,fail-closed)
user 要求有效的最终用户身份:当设置了 auth.web_user_secret_env 时使用 HMAC X-User-Token,否则信任 X-User-Id(开发环境)。返回 request.user_id / request.user

auth: user 从第一个版本起就可用。


21.5 路由与生命周期


21.6 访问日志

对自定义路由的每个请求都会写入 logs/access.jsonl / logs/access.db,与内置路由一样,但使用路由名称及其作用域 (global / <agent>)代替自由路径。请求体、请求头和令牌值 不会被记录。


21.7 测试(无需服务器)

agent-os route config/routes/weather.yaml '{"method":"GET","path":"/ext/weather/moscow"}'
agent-os route config/agents/felix/routes/card.yaml --method POST --body '{"user_id":"x"}'
agent-os route config/routes/dash.yaml --args-file req.json  # request JSON из файла ('-' = stdin)

agent-os route 打印模拟请求、脚本结果(status + headers + body) 和脚本错误——相当于路由的 agent-os hook / agent-os tool。对于 static_route,显示在 dir 下解析出哪些文件。带有 ?/& 的查询参数通过 --args-file 传递更方便,以免被 shell 破坏。