确认收到投递的工作行
确认收到已投递的工作行(queued → starting),记录 acknowledged_at——不在固定 ack 窗口(5000ms,由后台 sweeper 回收)内确认,工作行将被退回队列。投递后须立即 Ack,慢 executor 启动须在 Ack 之后。过期 token 将被拒绝并返回 412 failed_precondition_error。
curl --request POST \
--url https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"worker_id": "worker-1",
"generation": 1
}
'import requests
url = "https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack"
payload = {
"worker_id": "worker-1",
"generation": 1
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({worker_id: 'worker-1', generation: 1})
};
fetch('https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'worker_id' => 'worker-1',
'generation' => 1
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack"
payload := strings.NewReader("{\n \"worker_id\": \"worker-1\",\n \"generation\": 1\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"worker_id\": \"worker-1\",\n \"generation\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"worker_id\": \"worker-1\",\n \"generation\": 1\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"session_id": "<string>",
"environment_id": "<string>",
"status": "queued",
"generation": 2,
"lease_ttl_ms": 123,
"created_at": "2023-11-07T05:31:56Z",
"worker_id": "<string>",
"claimed_at": "2023-11-07T05:31:56Z",
"acknowledged_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"latest_heartbeat_at": "2023-11-07T05:31:56Z",
"stop_requested_at": "2023-11-07T05:31:56Z",
"stopped_at": "2023-11-07T05:31:56Z",
"secret": "<string>"
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}请求头
本次请求使用的 API 版本,格式为 YYYY-MM-DD。发送 2026-09-01-beta 即使用本文档所述版本。/v1/files* 之外必传:未携带请求头将被拒绝并返回 400 invalid_request_error;在 /v1/files* 上缺省时选择兼容行为。所有端点对未知取值均返回 400 invalid_request_error。
平台当前支持的 API 版本。新的日期版本发布时加入;版本在公告的 Sunset 日期后移除。
2026-09-01-beta 请求体
响应
已确认的工作行,状态转为 starting。
自托管工作队列中的一行:其沙箱工具调用在环境属主的 worker 上执行的会话。GET /v1/environments/{environment_id}/work/poll 投递工作行(ack 前仍为 queued);其携带的 generation 是 fencing token,后续每次 ack、心跳、stop 都必须携带。user.tool_result 回写无需显式携带:secret 中的会话级 work token 已绑定签发代次,平台由它派生 fencing。
工作行 ID。
该工作行所属的会话。
可认领该工作行的环境。
生命周期状态;poll 只返回 queued。
queued, starting, active, stopping, completed, failed, cancelled fencing token:从 1 开始,平台每次将失联 worker 的工作行重新入队时加 1。在心跳、ack、stop 时携带当前值;过期的 token 将被拒绝并返回 412 failed_precondition_error。工具结果回写改由会话级 work token 承载 fencing,该路径无需显式携带 generation。
x >= 1租约时长(毫秒);心跳会续租。
工作行的入队时间。
持有租约的 worker。
当前认领的发生时间。
worker 确认投递的时间——在投递窗口内由 ack 调用打戳。
首次心跳把行激活为 active 的时间(starting → active 时打戳)。
最近一次心跳落库时间;首次心跳前缺省。
首次停止请求时间,租约回收后保留。
工作行进入终态的时间;活跃期间缺省。
工作行所属会话的凭据包,仅在认领该工作行的 poll 响应中出现:base64url 编码的 JSON 对象。worker 解码该包,将其 sessions_token 成员作为 Authorization: Bearer 凭据用于该会话的写路径(如 POST /v1/sessions/{id}/events)以及该工作行的 ack/heartbeat/stop,作用域仅限该会话。包内其余成员保留,不得消费。凭据在工作行终结或被回收后失效——回收会将工作行交给持有新凭据的接替 worker,本凭据随即作废。任何其他端点都不会返回它。按机密处理:不要记录日志或持久化。
此页面对您有帮助吗?
curl --request POST \
--url https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"worker_id": "worker-1",
"generation": 1
}
'import requests
url = "https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack"
payload = {
"worker_id": "worker-1",
"generation": 1
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({worker_id: 'worker-1', generation: 1})
};
fetch('https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'worker_id' => 'worker-1',
'generation' => 1
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack"
payload := strings.NewReader("{\n \"worker_id\": \"worker-1\",\n \"generation\": 1\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"worker_id\": \"worker-1\",\n \"generation\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.moonshot.cn/v1/environments/{environment_id}/work/{id}/ack")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"worker_id\": \"worker-1\",\n \"generation\": 1\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"session_id": "<string>",
"environment_id": "<string>",
"status": "queued",
"generation": 2,
"lease_ttl_ms": 123,
"created_at": "2023-11-07T05:31:56Z",
"worker_id": "<string>",
"claimed_at": "2023-11-07T05:31:56Z",
"acknowledged_at": "2023-11-07T05:31:56Z",
"started_at": "2023-11-07T05:31:56Z",
"latest_heartbeat_at": "2023-11-07T05:31:56Z",
"stop_requested_at": "2023-11-07T05:31:56Z",
"stopped_at": "2023-11-07T05:31:56Z",
"secret": "<string>"
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_parameter_error",
"message": "<string>",
"param": "<string>",
"request_id": "<string>"
}
}