Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions apps/daemon/internal/cli/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,6 @@ func pumpConn(parentCtx context.Context, conn *transport.Conn, registry *agent.R
conn.StartHeartbeats(parentCtx, boot.HeartbeatInterval(), func() proto.HeartbeatPayload {
kinds := advertisedKinds(registry, local.CanExport())
return proto.HeartbeatPayload{
Timestamp: time.Now().Unix(),
ActiveRequests: router.ActiveRuns(),
DaemonVersion: Version,
SupportedAgentKinds: kinds,
}
}, obslog.Bg().With("component", "heartbeat"))
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/cli/connect_suspend.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (s *suspendedRouter) reconnectSuspension(ctx context.Context, dial transpor
func (s *suspendedRouter) heartbeats(ctx context.Context, conn *transport.Conn, boot *transport.BootstrapResponse, discovery agentCLIDiscovery) {
conn.StartHeartbeats(ctx, boot.HeartbeatInterval(), func() proto.HeartbeatPayload {
kinds := advertisedKinds(s.registry, s.local.CanExport())
return proto.HeartbeatPayload{Timestamp: time.Now().Unix(), ActiveRequests: s.router.ActiveRuns(), DaemonVersion: Version, SupportedAgentKinds: kinds}
return proto.HeartbeatPayload{SupportedAgentKinds: kinds}
}, obslog.Bg())
}

Expand Down
2 changes: 0 additions & 2 deletions apps/daemon/internal/transport/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ import (
// BootstrapResponse mirrors gateway/handler.go's Bootstrap response.
type BootstrapResponse struct {
DeviceID string `json:"device_id"`
WorkspaceID string `json:"workspace_id"`
WSURL string `json:"ws_url"`
HeartbeatSeconds int `json:"heartbeat_seconds"`
ProtocolVersion string `json:"protocol_version"`
}

// HeartbeatInterval defends against the server returning 0 — a zero
Expand Down
5 changes: 1 addition & 4 deletions apps/daemon/internal/transport/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@ func TestBootstrapSendsBearerAndDeviceID(t *testing.T) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{
"device_id": "rt_abc",
"workspace_id": "ws_xyz",
"ws_url": "wss://example/agent-daemon/ws",
"heartbeat_seconds": 15,
"protocol_version": "0.3.0",
})
}))
defer srv.Close()
Expand All @@ -44,7 +42,7 @@ func TestBootstrapSendsBearerAndDeviceID(t *testing.T) {
if err != nil {
t.Fatalf("Bootstrap: %v", err)
}
if resp.DeviceID != "rt_abc" || resp.WorkspaceID != "ws_xyz" {
if resp.DeviceID != "rt_abc" {
t.Errorf("unexpected response: %+v", resp)
}
if resp.WSURL != "wss://example/agent-daemon/ws" {
Expand All @@ -68,7 +66,6 @@ func TestBootstrapHeartbeatIntervalDefaultsToFifteen(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
_ = json.NewEncoder(w).Encode(map[string]any{
"device_id": "rt",
"workspace_id": "ws",
"ws_url": "",
"heartbeat_seconds": 0, // server forgot to set it
})
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/transport/ws.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func (c *Conn) Close() error {
// StartHeartbeats kicks off a ticker that calls payloadFn every
// interval and Sends the resulting HeartbeatPayload. Returns
// immediately. Caller-controlled because the heartbeat carries fields
// (active_requests, supported_agent_kinds) only the agent layer knows.
// (supported_agent_kinds) only the agent layer knows.
// Nil logger falls back to log.Bg().
func (c *Conn) StartHeartbeats(parentCtx context.Context, interval time.Duration, payloadFn func() proto.HeartbeatPayload, logger *slog.Logger) {
if interval <= 0 || payloadFn == nil {
Expand Down
4 changes: 2 additions & 2 deletions apps/daemon/internal/transport/ws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func TestStartHeartbeatsTicks(t *testing.T) {
var calls atomic.Int32
conn.StartHeartbeats(context.Background(), 30*time.Millisecond, func() proto.HeartbeatPayload {
calls.Add(1)
return proto.HeartbeatPayload{Timestamp: time.Now().Unix(), DaemonVersion: "0.0.0-dev"}
return proto.HeartbeatPayload{}
}, nil)

deadline := time.Now().Add(time.Second)
Expand Down Expand Up @@ -306,7 +306,7 @@ func TestStartHeartbeatsSendsImmediately(t *testing.T) {
defer cancel()
conn.StartHeartbeats(hbCtx, time.Hour, func() proto.HeartbeatPayload {
calls.Add(1)
return proto.HeartbeatPayload{Timestamp: time.Now().Unix(), DaemonVersion: "0.0.0-dev"}
return proto.HeartbeatPayload{}
}, nil)

deadline := time.Now().Add(2 * time.Second)
Expand Down
4 changes: 1 addition & 3 deletions apps/web/src/i18n/locales/en/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const diagnostics = {
server_error: "The model provider reported a server error.",
invalid_request: "The model provider rejected the request.",
resource_not_found: "The model provider could not find the model.",
request_timeout: "The model provider request timed out.",
context_length_exceeded: "The input exceeds the model's context limit.",
cyber_policy: "The model provider rejected the input under its safety policy.",
connection_failed: "The connection to the model provider failed.",
Expand All @@ -44,7 +43,6 @@ export const diagnostics = {
server_error: "Retry later.",
invalid_request: "Check the model and parameters, starting with the model on the Session page. Without a model provider set on the Session or its saved Agent, a hosted sandbox Session uses the default in Settings → Models and credentials.",
resource_not_found: "Check the model on the Session page. Without a model provider set on the Session or its saved Agent, a hosted sandbox Session uses the default in Settings → Models and credentials.",
request_timeout: "Retry later.",
context_length_exceeded: "Start a new Session or shorten the input.",
cyber_policy: "Change the input before sending it again, or start a new Session.",
connection_failed: "Check the Base URL of the Session's model provider. Without one set on the Session or its saved Agent, a hosted sandbox Session uses the default in Settings → Models and credentials.",
Expand All @@ -61,7 +59,7 @@ export const diagnostics = {
exitCode: "Exit code {{code}}.",
httpStatus: "HTTP {{status}}.",
unreachableHost: "Then check that the URL's host resolves and is reachable from the Session's sandbox, or from the host of a self-hosted Session.",
step: { setup: "setup", python: "Python dependencies", npm: "npm dependencies", system: "system packages", file: "file preparation", skill: "Skill preparation" },
step: { setup: "setup", python: "Python dependencies", npm: "npm dependencies", file: "file preparation", skill: "Skill preparation" },
unavailable: "Failure details unavailable",
unavailableHelp: "The diagnostics read failed or no longer matches this status. Refresh to check again.",
checking: "Checking failure details",
Expand Down
4 changes: 1 addition & 3 deletions apps/web/src/i18n/locales/zh-CN/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const diagnostics = {
server_error: "模型提供商发生了服务器错误。",
invalid_request: "模型提供商拒绝了请求。",
resource_not_found: "模型提供商找不到该模型。",
request_timeout: "模型提供商请求超时。",
context_length_exceeded: "输入超出模型的上下文上限。",
cyber_policy: "模型提供商因安全策略拒绝了输入。",
connection_failed: "与模型提供商的连接失败。",
Expand All @@ -44,7 +43,6 @@ export const diagnostics = {
server_error: "请稍后重试。",
invalid_request: "请检查模型和参数,先看 Session 页显示的模型。Session 及其保存的 Agent 都未设置模型提供商时,托管沙箱 Session 使用“设置 → 模型与凭据”中的默认配置。",
resource_not_found: "请检查 Session 页显示的模型。Session 及其保存的 Agent 都未设置模型提供商时,托管沙箱 Session 使用“设置 → 模型与凭据”中的默认配置。",
request_timeout: "请稍后重试。",
context_length_exceeded: "请新建 Session 或缩短输入。",
cyber_policy: "请修改输入后再发送,或新建 Session。",
connection_failed: "请检查该 Session 所用模型提供商的 Base URL。Session 及其保存的 Agent 都未设置模型提供商时,托管沙箱 Session 使用“设置 → 模型与凭据”中的默认配置。",
Expand All @@ -61,7 +59,7 @@ export const diagnostics = {
exitCode: "退出码 {{code}}。",
httpStatus: "HTTP {{status}}。",
unreachableHost: "再确认 Session 的沙箱(自托管 Session 则为其主机)能解析并访问该 URL 的主机。",
step: { setup: "设置", python: "Python 依赖", npm: "npm 依赖", system: "系统软件包", file: "文件准备", skill: "Skill 准备" },
step: { setup: "设置", python: "Python 依赖", npm: "npm 依赖", file: "文件准备", skill: "Skill 准备" },
unavailable: "失败详情不可用",
unavailableHelp: "诊断读取失败或与当前状态不一致,请刷新后重试。",
checking: "正在读取失败详情",
Expand Down
3 changes: 1 addition & 2 deletions contracts/agents-api/core-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ These have null `param` and no `details`. A Core `401 invalid_admin_key` therefo

## Sandbox provider verification

A `POST` or `PUT /core/v1/sandbox/deployment` ([sandbox deployment](./sandbox-deployment.md#reset)) whose provider verifies a credential or configuration, as E2B does, fails with these fixed errors. None returns provider text, a template name, a key or a resource count.
A `POST` or `PUT /core/v1/sandbox/deployment` ([sandbox deployment](./sandbox-deployment.md#e2b-key-replacement)) whose provider verifies a credential or configuration, as E2B does, fails with these fixed errors. None returns provider text, a template name, a key or a resource count.

| HTTP | Code | Meaning | `param` |
| --- | --- | --- | --- |
Expand Down Expand Up @@ -118,7 +118,6 @@ The [Session diagnostics](./session-diagnostics.md) routes return these categori
| `server_error` | Native server failure classification |
| `invalid_request` | Native request rejection |
| `resource_not_found` | Native resource/model not found |
| `request_timeout` | Reserved neutral timeout category; no current adapter producer |
| `context_length_exceeded` | Native context limit classification |
| `cyber_policy` | Native cyber policy rejection |
| `connection_failed` | Native connection failure; params contain `http_status`, an integer in 100–599 or null |
Expand Down
4 changes: 0 additions & 4 deletions contracts/agents-api/core.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,6 @@ definitions:
- server_error
- invalid_request
- resource_not_found
- request_timeout
- context_length_exceeded
- cyber_policy
- connection_failed
Expand Down Expand Up @@ -832,7 +831,6 @@ definitions:
- server_error
- invalid_request
- resource_not_found
- request_timeout
- context_length_exceeded
- cyber_policy
- connection_failed
Expand Down Expand Up @@ -1748,7 +1746,6 @@ definitions:
- server_overloaded
- server_error
- resource_not_found
- request_timeout
- invalid_request
type: string
x-enum-varnames:
Expand All @@ -1759,7 +1756,6 @@ definitions:
- ProviderServerOverloaded
- ProviderServerError
- ProviderResourceNotFound
- ProviderRequestTimeout
- ProviderInvalidRequest
modelprovider.Protocol:
enum:
Expand Down
2 changes: 1 addition & 1 deletion contracts/agents-api/machine-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ The credential is checked before any deployment state, so a rejected credential,

### Daemon bootstrap

`POST /api/v1/agent-daemon/bootstrap` with the daemon credential and `{"device_id": "…"}` returns `device_id`, `workspace_id`, `ws_url` (derived from `OAC_PUBLIC_URL`, never from request headers), `heartbeat_seconds` and `protocol_version`. The daemon then dials `ws_url` as the [Core–Runtime protocol](../../docs/runtime-protocol.md#ownership-and-connection) describes.
`POST /api/v1/agent-daemon/bootstrap` with the daemon credential and `{"device_id": "…"}` returns `device_id`, `ws_url` (derived from `OAC_PUBLIC_URL`, never from request headers) and `heartbeat_seconds`. The daemon then dials `ws_url` as the [Core–Runtime protocol](../../docs/runtime-protocol.md#ownership-and-connection) describes.

The bootstrap and WebSocket routes share one error body, `{"error": code, "detail": text}`: 400 `missing_params`, `missing_device_id` or `bad_json`; 401 `missing_bearer`, `unknown_device` or `bad_credential`; 403 `wrong_runtime_type`; 500 `internal`; and on the WebSocket 426 `incompatible_version` when `version` is not Core's exact Runtime protocol version.

Expand Down
2 changes: 1 addition & 1 deletion contracts/agents-api/model-execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Session creation decrypts the default of the resolved Harness and freezes it in
The Harness and default-model reads include nullable `last_used_at`, `last_error_code` and `last_error_at`; PUT resets all three, even for the same bundle.

- Completed root Turns record use only when their Session froze the exact current default revision.
- Failed root Turns record only the native provider codes `authentication_error`, `connection_failed`, `rate_limit_exceeded`, `usage_limit_exceeded`, `server_overloaded`, `server_error`, `resource_not_found`, `request_timeout` and `invalid_request`. Input-policy, Core or Runtime, cancelled and waiting outcomes do not count.
- Failed root Turns record only the native provider codes `authentication_error`, `connection_failed`, `rate_limit_exceeded`, `usage_limit_exceeded`, `server_overloaded`, `server_error`, `resource_not_found` and `invalid_request`. Input-policy, Core or Runtime, cancelled and waiting outcomes do not count.
- A success keeps the earlier error; comparing the timestamps is a display convention.
- Errors are throttled for 30 seconds regardless of code, and ordinary successes for 30 seconds; the first success after an error records recovery at once. For an unchanged revision this allows at most three effective writes in any 30-second window of database time.
- Each observation has a one-second budget, including pool and row-lock acquisition, and cannot change the committed Turn. A crash, failure or throttle can omit the latest observation.
Expand Down
2 changes: 1 addition & 1 deletion contracts/agents-api/session-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The object is `core.session_diagnostics`, with `session_id`, the official Sessio

A hosted provisioning failure takes precedence over input activity, and input activity over the latest root Turn; the public Session response uses the same precedence. Private outcome text, native messages, provider bodies, command text, paths and credentials are never included. Unknown outcome codes become `internal_error`; no prefix matching or reason-text parsing is used.

Provisioning parameters come from the confirmed structured receipt, persisted in the failure transaction that settles the Environment and its input and records the events. `step` is `setup`, `python`, `npm`, `system`, `file`, `skill` or null. `index` is a nonnegative JSON-safe integer for setup only, otherwise null. `exit_code` is 1 to 255 for script steps, otherwise null. Details that were not recorded remain null. These private fields do not change the public failure reason or SSE.
Provisioning parameters come from the confirmed structured receipt, persisted in the failure transaction that settles the Environment and its input and records the events. `step` is `setup`, `python`, `npm`, `file`, `skill` or null. `index` is a nonnegative JSON-safe integer for setup only, otherwise null. `exit_code` is 1 to 255 for script steps, otherwise null. Details that were not recorded remain null. These private fields do not change the public failure reason or SSE.

## Turn snapshot and Item receipt timing

Expand Down
5 changes: 2 additions & 3 deletions contracts/agents-api/zh/core-errors.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Core 管理错误"
source: contracts/agents-api/core-errors.md
source_hash: 9229fb99268c1b3f5a97a4c97e762faaf0e45bada46e6b1f82d28798e090d205
source_hash: 1532078430d8e8a5570e652db60a99b282d57897ca6f3360cd0b1a94a948d02d
---

`/core/v1` 上的错误使用此封装结构。`message` 是安全的英文文本;`code` 和 `param` 可以为 null。客户端依据稳定的 `code` 和可选的 `param` 进行处理,对未知代码显示 `message`,绝不解析消息,也绝不自动重试被拒绝的写操作。
Expand Down Expand Up @@ -40,7 +40,7 @@ Web 的控制台服务器在 `/core` 路径上发生自身故障时使用此封

## 沙箱提供商验证 {#sandbox-provider-verification}

当 `POST` 或 `PUT /core/v1/sandbox/deployment`([sandbox deployment](sandbox-deployment.md#reset))的提供商像 E2B 一样验证凭据或配置时,请求会因以下固定错误而失败。这些错误均不会返回提供商文本、模板名称、密钥或资源数量。
当 `POST` 或 `PUT /core/v1/sandbox/deployment`([sandbox deployment](sandbox-deployment.md#e2b-key-replacement))的提供商像 E2B 一样验证凭据或配置时,请求会因以下固定错误而失败。这些错误均不会返回提供商文本、模板名称、密钥或资源数量。

| HTTP | 代码 | 含义 | `param` |
| --- | --- | --- | --- |
Expand Down Expand Up @@ -120,7 +120,6 @@ Web 的控制台服务器在 `/core` 路径上发生自身故障时使用此封
| `server_error` | 原生服务器故障分类 |
| `invalid_request` | 原生请求被拒绝 |
| `resource_not_found` | 未找到原生资源或模型 |
| `request_timeout` | 保留的中性超时类别;当前没有适配器生成该类别 |
| `context_length_exceeded` | 原生上下文限制分类 |
| `cyber_policy` | 原生网络安全策略拒绝 |
| `connection_failed` | 原生连接故障;params 包含 `http_status`,其值为 100–599 范围内的整数或 null |
Expand Down
4 changes: 2 additions & 2 deletions contracts/agents-api/zh/machine-api.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "机器连接 API"
source: contracts/agents-api/machine-api.md
source_hash: f3e9a3cd478fcc16f466cf749e49ace8cd49bd8769e9698f6e7a0edacad3c5f7
source_hash: f0b384850366cbbbe9a868c018963bd446b052432ed1617285f8e8bcf7c1569c
---

机器通过 `/api/v1` 调用 Core:包括沙箱节点、Runtime daemon 和自托管安装程序。各路由仅接受所列凭据,不接受 Core 密钥或项目 API 密钥;控制台登录也不授予此处权限。反向代理将 `/api/v1` 直接发送给 Core;Web 不提供这些路由。
Expand Down Expand Up @@ -103,7 +103,7 @@ Core 在一个事务中检查 token 有效、部署已初始化且为节点型

### daemon 引导 {#daemon-bootstrap}

`POST /api/v1/agent-daemon/bootstrap` 携带 daemon 凭据及 `{"device_id": "…"}`,返回 `device_id`、`workspace_id`、`ws_url`(从 `OAC_PUBLIC_URL` 推导,不使用请求头)、`heartbeat_seconds` 和 `protocol_version`。daemon 随后按 [Core–Runtime 协议](../../../docs/zh/runtime-protocol.md#ownership-and-connection)连接 `ws_url`。
`POST /api/v1/agent-daemon/bootstrap` 携带 daemon 凭据及 `{"device_id": "…"}`,返回 `device_id`、`ws_url`(从 `OAC_PUBLIC_URL` 推导,不使用请求头)和 `heartbeat_seconds`。daemon 随后按 [Core–Runtime 协议](../../../docs/zh/runtime-protocol.md#ownership-and-connection)连接 `ws_url`。

引导和 WebSocket 路由共享错误体 `{"error": code, "detail": text}`:400 `missing_params`、`missing_device_id` 或 `bad_json`;401 `missing_bearer`、`unknown_device` 或 `bad_credential`;403 `wrong_runtime_type`;500 `internal`;WebSocket 的 `version` 不等于 Core 精确 Runtime 协议版本时返回 426 `incompatible_version`。

Expand Down
Loading
Loading