fix: interactive Realm password, recoverable worker budget (0.9.15)
Prompt for Realm password when CST_REALM_PASSWORD is unset; map worker request-gate exhaustion to a clear budget error with partial progress; hard-skip identical tool failures after 3 tries. Add docs/parliament.md. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -48,6 +48,7 @@ irm https://git.whcself.xyz/WHC/CST-agent/raw/branch/main/scripts/install_window
|
|||||||
界面里用 `/provider` 切换(没保存过 key 的会当场询问),`/model`、`/effort` 切换模型和推理强度,`/key` 更换 key。
|
界面里用 `/provider` 切换(没保存过 key 的会当场询问),`/model`、`/effort` 切换模型和推理强度,`/key` 更换 key。
|
||||||
|
|
||||||
完整环境变量说明:[docs/env_openai.md](docs/env_openai.md)。
|
完整环境变量说明:[docs/env_openai.md](docs/env_openai.md)。
|
||||||
|
多设备议会(密码 Realm / 主席 / 常驻同步):[docs/parliament.md](docs/parliament.md)。
|
||||||
|
|
||||||
| 平台 | 一键脚本 |
|
| 平台 | 一键脚本 |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
# Parliament(议会)快速上手
|
||||||
|
|
||||||
|
密码串派生 Realm → 登录夺主席 → 常驻服务同步上下文。同一时刻只有一个主席;换项目清空全部议会上下文。
|
||||||
|
|
||||||
|
## 一次性初始化
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 交互输入密码,或事先 export CST_REALM_PASSWORD=…
|
||||||
|
cst-agent --realm-password-init
|
||||||
|
```
|
||||||
|
|
||||||
|
磁盘只存 salt + 公钥,**不存私钥**。
|
||||||
|
|
||||||
|
## 日常:登录即夺主席
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export CST_INSTANCE_ID=laptop-a # 可选;默认 chair-local
|
||||||
|
cst-agent --login --realm-label "thinkpad"
|
||||||
|
# 也可:CST_REALM_PASSWORD=… cst-agent --login
|
||||||
|
```
|
||||||
|
|
||||||
|
效果:
|
||||||
|
|
||||||
|
1. 用密码解锁 Realm,本机成为**唯一主席**(上一主席被交接)
|
||||||
|
2. 写入本地登录票(24h)
|
||||||
|
3. 拉起后台议会服务(发现 + 按 revision 同步 `parliament.context`)
|
||||||
|
|
||||||
|
查看状态:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cst-agent # 进入 TUI 后 /status
|
||||||
|
# 或 CLI
|
||||||
|
cst-agent --service-stop # 停服务
|
||||||
|
```
|
||||||
|
|
||||||
|
密码 Realm 开启后,直接打开 agent 会要求登录(TTY 下可当场输入密码)。
|
||||||
|
|
||||||
|
## 协作模式
|
||||||
|
|
||||||
|
`settings.json` 里 `"collaboration": "parliament"`(或环境变量 `CST_COLLABORATION=parliament`)时:
|
||||||
|
|
||||||
|
- 提示词不再鼓动 `task` / `worker_start`
|
||||||
|
- 本机用工具直接干活;跨设备靠 Realm peer 席位,而不是进程内子 agent
|
||||||
|
|
||||||
|
密码 Realm 存在时也会按议会模式注入 Environment(chair / 共享 context / 设备席位)。
|
||||||
|
|
||||||
|
## 换项目(清场)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cst-agent --new-project my-app
|
||||||
|
```
|
||||||
|
|
||||||
|
清空共享上下文、撤销主席与登录票,并停止本机服务。Realm 密钥保留。
|
||||||
|
|
||||||
|
## Docker 冒烟
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/docker_parliament_test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Alpine 内构建,chair↔member 握手。
|
||||||
|
|
||||||
|
## 相关标志
|
||||||
|
|
||||||
|
| 标志 | 作用 |
|
||||||
|
|------|------|
|
||||||
|
| `--realm-password-init` | 创建密码 Realm |
|
||||||
|
| `--login` | 登录 + 夺主席 + 启服务 |
|
||||||
|
| `--service` / `--service-fg` | 仅启服务 |
|
||||||
|
| `--service-stop` | 停服务 |
|
||||||
|
| `--new-project ID` | 清场换项目 |
|
||||||
|
| `--peer-port N` | 登录/服务用的 TCP 端口(默认 9100) |
|
||||||
|
| `--instance ID` | 实例 id(也可用 `CST_INSTANCE_ID`) |
|
||||||
@@ -477,6 +477,8 @@ int cst_creds_resolve(const char *provider, char *out, size_t out_sz,
|
|||||||
const char **from);
|
const char **from);
|
||||||
/* Hidden console prompt (no echo). */
|
/* Hidden console prompt (no echo). */
|
||||||
int cst_creds_prompt_console(const char *provider, char *out, size_t out_sz);
|
int cst_creds_prompt_console(const char *provider, char *out, size_t out_sz);
|
||||||
|
/* Generic hidden prompt for passwords / secrets (TTY only). */
|
||||||
|
int cst_prompt_secret(const char *prompt, char *out, size_t out_sz);
|
||||||
|
|
||||||
/* Last used provider, model per provider, effort and working mode, in
|
/* Last used provider, model per provider, effort and working mode, in
|
||||||
* <config>/settings.json. */
|
* <config>/settings.json. */
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#define CST_VERSION_MAJOR 0
|
#define CST_VERSION_MAJOR 0
|
||||||
#define CST_VERSION_MINOR 9
|
#define CST_VERSION_MINOR 9
|
||||||
#define CST_VERSION_PATCH 14
|
#define CST_VERSION_PATCH 15
|
||||||
|
|
||||||
#define CST_VERSION_STR_(x) #x
|
#define CST_VERSION_STR_(x) #x
|
||||||
#define CST_VERSION_STR(x) CST_VERSION_STR_(x)
|
#define CST_VERSION_STR(x) CST_VERSION_STR_(x)
|
||||||
|
|||||||
@@ -1193,6 +1193,15 @@ static void exec_begin(turn_t *t, pcall_t *pc, exec_t *x) {
|
|||||||
!(def->parallel && def->parallel(c, def->ud)));
|
!(def->parallel && def->parallel(c, def->ud)));
|
||||||
uint64_t h = call_hash(c);
|
uint64_t h = call_hash(c);
|
||||||
x->h = h;
|
x->h = h;
|
||||||
|
if (fail_count(a, h, 0) >= 3) {
|
||||||
|
const char *msg =
|
||||||
|
"error: this exact call already failed 3+ times this turn; skipped. "
|
||||||
|
"Change approach instead of repeating the same call.";
|
||||||
|
set_output(pc, msg, strlen(msg), 1);
|
||||||
|
pc->status = PC_DENIED;
|
||||||
|
hook_status(t, "skip repeated failure");
|
||||||
|
return;
|
||||||
|
}
|
||||||
int dup = 0;
|
int dup = 0;
|
||||||
/* plugin and MCP results can change between identical calls */
|
/* plugin and MCP results can change between identical calls */
|
||||||
int external = def->owner && strncmp(def->owner, "builtin:", 8) != 0;
|
int external = def->owner && strncmp(def->owner, "builtin:", 8) != 0;
|
||||||
@@ -3173,6 +3182,26 @@ static int run_turn_once(cst_agent_t *a, const char *user_text,
|
|||||||
t.ncalls = kept;
|
t.ncalls = kept;
|
||||||
if (t.ncalls > 0)
|
if (t.ncalls > 0)
|
||||||
persist_calls(&t);
|
persist_calls(&t);
|
||||||
|
/* Worker request-gate exhaustion is recoverable: keep partial progress
|
||||||
|
* and return a clear budget error instead of a generic llm: failure. */
|
||||||
|
int budget =
|
||||||
|
lerr[0] && (strstr(lerr, "budget:") || strstr(lerr, "budget exhausted"));
|
||||||
|
if (budget) {
|
||||||
|
const char *body = t.text.buf ? trim_left(t.text.buf) : "";
|
||||||
|
if (text_is_meaningful(body, strlen(body)))
|
||||||
|
append_reply(&t, body, NULL, meta_json("budget", proto));
|
||||||
|
else if (tools_ran || t.ncalls > 0) {
|
||||||
|
append_msg(a, CST_ROLE_ASSISTANT,
|
||||||
|
"Stopped: shared worker request budget is exhausted. "
|
||||||
|
"Partial tool work above is kept; raise max_requests or "
|
||||||
|
"finish without further worker HTTP calls.",
|
||||||
|
NULL, NULL, NULL, meta_json("budget", proto));
|
||||||
|
}
|
||||||
|
turn_free(&t);
|
||||||
|
snprintf(err, err_sz, "budget: worker request budget exhausted");
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
turn_free(&t);
|
turn_free(&t);
|
||||||
snprintf(err, err_sz, "llm: %s", lerr);
|
snprintf(err, err_sz, "llm: %s", lerr);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+10
-3
@@ -160,12 +160,11 @@ int cst_creds_resolve(const char *provider, char *out, size_t out_sz,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cst_creds_prompt_console(const char *provider, char *out, size_t out_sz) {
|
int cst_prompt_secret(const char *prompt, char *out, size_t out_sz) {
|
||||||
if (!out || out_sz < 2)
|
if (!out || out_sz < 2)
|
||||||
return -1;
|
return -1;
|
||||||
out[0] = 0;
|
out[0] = 0;
|
||||||
fprintf(stderr, "API key for %s (input hidden, saved to the config dir): ",
|
fprintf(stderr, "%s", prompt && prompt[0] ? prompt : "Secret: ");
|
||||||
provider ? provider : "?");
|
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE hin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
@@ -198,3 +197,11 @@ int cst_creds_prompt_console(const char *provider, char *out, size_t out_sz) {
|
|||||||
chomp(out);
|
chomp(out);
|
||||||
return out[0] ? 0 : -1;
|
return out[0] ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cst_creds_prompt_console(const char *provider, char *out, size_t out_sz) {
|
||||||
|
char prompt[128];
|
||||||
|
snprintf(prompt, sizeof(prompt),
|
||||||
|
"API key for %s (input hidden, saved to the config dir): ",
|
||||||
|
provider ? provider : "?");
|
||||||
|
return cst_prompt_secret(prompt, out, out_sz);
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -1137,7 +1137,7 @@ int cst_llm_chat_stream(const cst_llm_request_t *req, char *err,
|
|||||||
|
|
||||||
if (rep_dir && rep_dir[0]) {
|
if (rep_dir && rep_dir[0]) {
|
||||||
if (req->request_gate && !req->request_gate(req->request_gate_ud)) {
|
if (req->request_gate && !req->request_gate(req->request_gate_ud)) {
|
||||||
snprintf(err, err_sz, "worker request budget exhausted");
|
snprintf(err, err_sz, "budget: worker request budget exhausted");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
@@ -1158,7 +1158,7 @@ int cst_llm_chat_stream(const cst_llm_request_t *req, char *err,
|
|||||||
|
|
||||||
for (int attempt = 0;; attempt++) {
|
for (int attempt = 0;; attempt++) {
|
||||||
if (req->request_gate && !req->request_gate(req->request_gate_ud)) {
|
if (req->request_gate && !req->request_gate(req->request_gate_ud)) {
|
||||||
snprintf(err, err_sz, "worker request budget exhausted");
|
snprintf(err, err_sz, "budget: worker request budget exhausted");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -52,7 +52,7 @@ static void usage(const char *argv0) {
|
|||||||
" --no-orchestrate override workspace orchestration setting\n"
|
" --no-orchestrate override workspace orchestration setting\n"
|
||||||
" --realm-new create Realm file keys (legacy/dev)\n"
|
" --realm-new create Realm file keys (legacy/dev)\n"
|
||||||
" --realm-password-init create password-derived Realm (no sk on disk)\n"
|
" --realm-password-init create password-derived Realm (no sk on disk)\n"
|
||||||
" --login unlock; claim chair; start parliament service\n"
|
" --login unlock (CST_REALM_PASSWORD or prompt); claim chair\n"
|
||||||
" --service run parliament service (discover+context sync)\n"
|
" --service run parliament service (discover+context sync)\n"
|
||||||
" --service-fg same as --service, stay in foreground\n"
|
" --service-fg same as --service, stay in foreground\n"
|
||||||
" --service-stop stop the parliament background service\n"
|
" --service-stop stop the parliament background service\n"
|
||||||
@@ -754,7 +754,12 @@ int main(int argc, char **argv) {
|
|||||||
char rdir[OS_PATH_MAX];
|
char rdir[OS_PATH_MAX];
|
||||||
if (cst_realm_dir(rdir, sizeof(rdir)) == 0 &&
|
if (cst_realm_dir(rdir, sizeof(rdir)) == 0 &&
|
||||||
cst_realm_is_password_mode(rdir) && !cst_parliament_session_ok(NULL, 0)) {
|
cst_realm_is_password_mode(rdir) && !cst_parliament_session_ok(NULL, 0)) {
|
||||||
|
char pwbuf[256];
|
||||||
const char *pw = getenv("CST_REALM_PASSWORD");
|
const char *pw = getenv("CST_REALM_PASSWORD");
|
||||||
|
if ((!pw || !pw[0]) && isatty(0) &&
|
||||||
|
cst_prompt_secret("Realm password to open agent (hidden): ", pwbuf,
|
||||||
|
sizeof(pwbuf)) == 0)
|
||||||
|
pw = pwbuf;
|
||||||
if (pw && pw[0]) {
|
if (pw && pw[0]) {
|
||||||
const char *iid = parliament_instance ? parliament_instance
|
const char *iid = parliament_instance ? parliament_instance
|
||||||
: getenv("CST_INSTANCE_ID");
|
: getenv("CST_INSTANCE_ID");
|
||||||
@@ -765,6 +770,8 @@ int main(int argc, char **argv) {
|
|||||||
cst_parliament_login(pw, iid, realm_label, err, sizeof(err));
|
cst_parliament_login(pw, iid, realm_label, err, sizeof(err));
|
||||||
if (!hand) {
|
if (!hand) {
|
||||||
fprintf(stderr, "%s\n", err[0] ? err : "login required");
|
fprintf(stderr, "%s\n", err[0] ? err : "login required");
|
||||||
|
if (pw == pwbuf)
|
||||||
|
memset(pwbuf, 0, sizeof(pwbuf));
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -773,6 +780,8 @@ int main(int argc, char **argv) {
|
|||||||
sizeof(err)) != 0)
|
sizeof(err)) != 0)
|
||||||
fprintf(stderr, "warning: parliament service: %s\n",
|
fprintf(stderr, "warning: parliament service: %s\n",
|
||||||
err[0] ? err : "start failed");
|
err[0] ? err : "start failed");
|
||||||
|
if (pw == pwbuf)
|
||||||
|
memset(pwbuf, 0, sizeof(pwbuf));
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"password Realm active: run --login (or set "
|
"password Realm active: run --login (or set "
|
||||||
|
|||||||
+51
-19
@@ -2,6 +2,7 @@
|
|||||||
#define _DEFAULT_SOURCE
|
#define _DEFAULT_SOURCE
|
||||||
#endif
|
#endif
|
||||||
#include "cst_parliament_cli.h"
|
#include "cst_parliament_cli.h"
|
||||||
|
#include "cst_agent.h"
|
||||||
#include "cst_discover.h"
|
#include "cst_discover.h"
|
||||||
#include "cst_net.h"
|
#include "cst_net.h"
|
||||||
#include "cst_parliament.h"
|
#include "cst_parliament.h"
|
||||||
@@ -29,6 +30,21 @@ static void sleep_ms(int ms) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prefer CST_REALM_PASSWORD; otherwise prompt on a TTY. */
|
||||||
|
static int resolve_password(char *buf, size_t n, const char **out) {
|
||||||
|
const char *env = getenv("CST_REALM_PASSWORD");
|
||||||
|
if (env && env[0]) {
|
||||||
|
*out = env;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (cst_prompt_secret("Realm password (input hidden): ", buf, n) != 0) {
|
||||||
|
fprintf(stderr, "password required (set CST_REALM_PASSWORD or type it)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*out = buf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int cst_parliament_cli_realm_new(void) {
|
int cst_parliament_cli_realm_new(void) {
|
||||||
char dir[OS_PATH_MAX], fp[33];
|
char dir[OS_PATH_MAX], fp[33];
|
||||||
if (cst_realm_dir(dir, sizeof(dir)) != 0) {
|
if (cst_realm_dir(dir, sizeof(dir)) != 0) {
|
||||||
@@ -46,24 +62,26 @@ int cst_parliament_cli_realm_new(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int cst_parliament_cli_realm_password_init(const char *password) {
|
int cst_parliament_cli_realm_password_init(const char *password) {
|
||||||
if (!password || !password[0]) {
|
char pwbuf[256];
|
||||||
fprintf(stderr, "password required (or CST_REALM_PASSWORD)\n");
|
const char *pw = password;
|
||||||
|
if ((!pw || !pw[0]) && resolve_password(pwbuf, sizeof(pwbuf), &pw) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
char dir[OS_PATH_MAX], fp[33];
|
char dir[OS_PATH_MAX], fp[33];
|
||||||
if (cst_realm_dir(dir, sizeof(dir)) != 0) {
|
if (cst_realm_dir(dir, sizeof(dir)) != 0) {
|
||||||
fprintf(stderr, "cannot resolve realm directory\n");
|
fprintf(stderr, "cannot resolve realm directory\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (cst_realm_init_password(dir, password) != 0) {
|
if (cst_realm_init_password(dir, pw) != 0) {
|
||||||
fprintf(stderr, "password realm init failed\n");
|
fprintf(stderr, "password realm init failed\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
cst_realm_keys_t k;
|
cst_realm_keys_t k;
|
||||||
if (cst_realm_unlock_password(dir, password, &k) != 0)
|
if (cst_realm_unlock_password(dir, pw, &k) != 0)
|
||||||
return 1;
|
return 1;
|
||||||
cst_realm_fingerprint(k.pk, fp);
|
cst_realm_fingerprint(k.pk, fp);
|
||||||
printf("realm_password_mode dir=%s fingerprint=%s\n", dir, fp);
|
printf("realm_password_mode dir=%s fingerprint=%s\n", dir, fp);
|
||||||
|
if (pw == pwbuf)
|
||||||
|
memset(pwbuf, 0, sizeof(pwbuf));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,52 +94,66 @@ int cst_parliament_cli_login(const char *password, const char *instance_id,
|
|||||||
int cst_parliament_cli_login_and_serve(const char *password,
|
int cst_parliament_cli_login_and_serve(const char *password,
|
||||||
const char *instance_id,
|
const char *instance_id,
|
||||||
const char *device_label, int peer_port) {
|
const char *device_label, int peer_port) {
|
||||||
char err[256];
|
char err[256], pwbuf[256];
|
||||||
char *hand = cst_parliament_login(password, instance_id, device_label, err,
|
const char *pw = password;
|
||||||
|
if ((!pw || !pw[0]) && resolve_password(pwbuf, sizeof(pwbuf), &pw) != 0)
|
||||||
|
return 1;
|
||||||
|
char *hand = cst_parliament_login(pw, instance_id, device_label, err,
|
||||||
sizeof(err));
|
sizeof(err));
|
||||||
if (!hand) {
|
if (!hand) {
|
||||||
fprintf(stderr, "%s\n", err[0] ? err : "login failed");
|
fprintf(stderr, "%s\n", err[0] ? err : "login failed");
|
||||||
|
if (pw == pwbuf)
|
||||||
|
memset(pwbuf, 0, sizeof(pwbuf));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fputs(hand, stdout);
|
fputs(hand, stdout);
|
||||||
free(hand);
|
free(hand);
|
||||||
if (cst_parliament_daemon_start(password, instance_id,
|
if (cst_parliament_daemon_start(pw, instance_id,
|
||||||
peer_port > 0 ? peer_port : 9100, err,
|
peer_port > 0 ? peer_port : 9100, err,
|
||||||
sizeof(err)) != 0) {
|
sizeof(err)) != 0) {
|
||||||
fprintf(stderr, "warning: service: %s (chair login still valid)\n",
|
fprintf(stderr, "warning: service: %s (chair login still valid)\n",
|
||||||
err[0] ? err : "start failed");
|
err[0] ? err : "start failed");
|
||||||
printf("service=failed\n");
|
printf("service=failed\n");
|
||||||
|
if (pw == pwbuf)
|
||||||
|
memset(pwbuf, 0, sizeof(pwbuf));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (cst_parliament_daemon_running())
|
if (cst_parliament_daemon_running())
|
||||||
printf("service=running\n");
|
printf("service=running\n");
|
||||||
|
if (pw == pwbuf)
|
||||||
|
memset(pwbuf, 0, sizeof(pwbuf));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cst_parliament_cli_service(const char *password, const char *instance_id,
|
int cst_parliament_cli_service(const char *password, const char *instance_id,
|
||||||
int peer_port, int foreground) {
|
int peer_port, int foreground) {
|
||||||
char err[256];
|
char err[256], pwbuf[256];
|
||||||
|
const char *pw = password;
|
||||||
if (!instance_id || !instance_id[0]) {
|
if (!instance_id || !instance_id[0]) {
|
||||||
fprintf(stderr, "instance id required\n");
|
fprintf(stderr, "instance id required\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if ((!pw || !pw[0]) && resolve_password(pwbuf, sizeof(pwbuf), &pw) != 0)
|
||||||
|
return 1;
|
||||||
|
int rc = 0;
|
||||||
if (foreground) {
|
if (foreground) {
|
||||||
if (cst_parliament_daemon_run(password, instance_id,
|
if (cst_parliament_daemon_run(pw, instance_id,
|
||||||
peer_port > 0 ? peer_port : 9100, err,
|
peer_port > 0 ? peer_port : 9100, err,
|
||||||
sizeof(err)) != 0) {
|
sizeof(err)) != 0) {
|
||||||
fprintf(stderr, "%s\n", err[0] ? err : "service failed");
|
fprintf(stderr, "%s\n", err[0] ? err : "service failed");
|
||||||
return 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
} else if (cst_parliament_daemon_start(pw, instance_id,
|
||||||
}
|
peer_port > 0 ? peer_port : 9100, err,
|
||||||
if (cst_parliament_daemon_start(password, instance_id,
|
sizeof(err)) != 0) {
|
||||||
peer_port > 0 ? peer_port : 9100, err,
|
|
||||||
sizeof(err)) != 0) {
|
|
||||||
fprintf(stderr, "%s\n", err[0] ? err : "service start failed");
|
fprintf(stderr, "%s\n", err[0] ? err : "service start failed");
|
||||||
return 1;
|
rc = 1;
|
||||||
|
} else {
|
||||||
|
printf("service=running\n");
|
||||||
}
|
}
|
||||||
printf("service=running\n");
|
if (pw == pwbuf)
|
||||||
return 0;
|
memset(pwbuf, 0, sizeof(pwbuf));
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cst_parliament_cli_service_stop(void) {
|
int cst_parliament_cli_service_stop(void) {
|
||||||
|
|||||||
+14
-4
@@ -1087,10 +1087,20 @@ static int task_run(const cst_tool_ctx_t *ctx, const ctl_tool_call_t *c,
|
|||||||
}
|
}
|
||||||
long tokens = cst_agent_last_prompt_tokens(run.child);
|
long tokens = cst_agent_last_prompt_tokens(run.child);
|
||||||
cst_buf_t b = {0};
|
cst_buf_t b = {0};
|
||||||
if (rc != 0)
|
if (rc != 0) {
|
||||||
cst_buf_printf(&b, "error: sub-agent %s: %s\n", cancelled ? "cancelled"
|
int budget = err[0] && (strstr(err, "budget:") ||
|
||||||
: "failed",
|
strstr(err, "budget exhausted"));
|
||||||
err[0] ? err : "unknown error");
|
if (budget) {
|
||||||
|
cst_buf_puts(&b, "error: worker request budget exhausted\n");
|
||||||
|
if (err[0])
|
||||||
|
cst_buf_printf(&b, "detail: %s\n", err);
|
||||||
|
cst_buf_puts(&b, "hint: raise .agent/workers.json max_requests, or "
|
||||||
|
"finish the remaining work yourself with local tools.\n");
|
||||||
|
} else
|
||||||
|
cst_buf_printf(&b, "error: sub-agent %s: %s\n",
|
||||||
|
cancelled ? "cancelled" : "failed",
|
||||||
|
err[0] ? err : "unknown error");
|
||||||
|
}
|
||||||
if (final) {
|
if (final) {
|
||||||
while (*final == ' ' || *final == '\n')
|
while (*final == ' ' || *final == '\n')
|
||||||
final++;
|
final++;
|
||||||
|
|||||||
Reference in New Issue
Block a user