feat: add v2 task control and asynchronous isolated workers
This commit is contained in:
+61
@@ -24,6 +24,8 @@
|
||||
#include "cst_sandbox.h"
|
||||
#include "cst_skills.h"
|
||||
#include "cst_subagent.h"
|
||||
#include "cst_runtime.h"
|
||||
#include "cst_worktree.h"
|
||||
#include "cst_tools.h"
|
||||
#include "cst_util.h"
|
||||
#include "cst_web_md.h"
|
||||
@@ -2358,6 +2360,61 @@ static int h_worker_cancel(cst_http_conn_t *c, void *ud) {
|
||||
return cst_http_send_str(c, 200, "application/json", "{\"ok\":true}");
|
||||
}
|
||||
|
||||
static int h_task_get(cst_http_conn_t *c, void *ud) {
|
||||
wui_t *w = ud;
|
||||
if (wui_claim_read(w)) return cst_http_send_err(c, 409, "session is changing");
|
||||
char *s = cst_runtime_json(cst_agent_config(w->agent)->runtime);
|
||||
cJSON *j = s ? cJSON_Parse(s) : NULL; free(s); wui_release(w);
|
||||
return wui_send_obj(c, 200, j ? j : cJSON_CreateObject());
|
||||
}
|
||||
static int h_task_control(cst_http_conn_t *c, void *ud) {
|
||||
wui_t *w = ud;
|
||||
if (wui_claim_read(w)) return cst_http_send_err(c, 409, "session is changing");
|
||||
cJSON *j = wui_body(c);
|
||||
const cJSON *msg = cJSON_GetObjectItemCaseSensitive(j, "message");
|
||||
const cJSON *ro = cJSON_GetObjectItemCaseSensitive(j, "read_only");
|
||||
const cJSON *delegate = cJSON_GetObjectItemCaseSensitive(j, "delegation");
|
||||
const cJSON *paused = cJSON_GetObjectItemCaseSensitive(j, "paused");
|
||||
int valid = cJSON_IsObject(j) && (!msg || cJSON_IsString(msg)) && (!ro || cJSON_IsBool(ro)) && (!delegate || cJSON_IsBool(delegate)) && (!paused || cJSON_IsBool(paused));
|
||||
int rc = -1;
|
||||
if (valid) {
|
||||
pthread_mutex_lock(&w->mu); int running = w->busy; pthread_mutex_unlock(&w->mu);
|
||||
if (msg && msg->valuestring[0] && !running) {
|
||||
if (ro || delegate || paused) cst_agent_control(w->agent, ro ? cJSON_IsTrue(ro) : -1, delegate ? cJSON_IsTrue(delegate) : -1, paused ? cJSON_IsTrue(paused) : -1);
|
||||
char error[256]; rc = wui_start_turn(w, msg->valuestring, 1, error, sizeof(error));
|
||||
} else if (msg && msg->valuestring[0]) rc = cst_agent_steer(w->agent, msg->valuestring, ro ? cJSON_IsTrue(ro) : -1, delegate ? cJSON_IsTrue(delegate) : -1);
|
||||
else rc = cst_agent_control(w->agent, ro ? cJSON_IsTrue(ro) : -1, delegate ? cJSON_IsTrue(delegate) : -1, paused ? cJSON_IsTrue(paused) : -1);
|
||||
}
|
||||
cJSON_Delete(j); wui_release(w);
|
||||
if (rc) return cst_http_send_err(c, 400, "expected message and/or boolean task controls");
|
||||
return cst_http_send_str(c, 202, "application/json", "{\"ok\":true}");
|
||||
}
|
||||
static int h_worktree(cst_http_conn_t *c, void *ud) {
|
||||
wui_t *w = ud;
|
||||
if (wui_claim(w)) return cst_http_send_err(c, 409, "wait for the active task");
|
||||
cJSON *j = wui_body(c);
|
||||
const cJSON *path = cJSON_GetObjectItemCaseSensitive(j, "worktree");
|
||||
int integrate = cJSON_IsTrue(cJSON_GetObjectItemCaseSensitive(j, "integrate"));
|
||||
const cst_agent_config_t *cfg = cst_agent_config(w->agent);
|
||||
int code = 1; char *text = NULL;
|
||||
if (cJSON_IsString(path) && (!integrate || cst_runtime_check(cfg->runtime, cst_runtime_revision(cfg->runtime), 1, 0)) && !cst_runtime_jobs_pending(cfg->runtime))
|
||||
text = cst_worktree_diff(cfg->workspace_root, path->valuestring, integrate, &code);
|
||||
cJSON_Delete(j); wui_release(w);
|
||||
cJSON *result = cJSON_CreateObject(); cJSON_AddBoolToObject(result, "ok", !code);
|
||||
cJSON_AddStringToObject(result, "output", text ? text : "task is read-only, jobs are active, or worktree is missing"); free(text);
|
||||
return wui_send_obj(c, code ? 409 : 200, result);
|
||||
}
|
||||
static int h_job_cancel(cst_http_conn_t *c, void *ud) {
|
||||
wui_t *w = ud;
|
||||
if (wui_claim_read(w)) return cst_http_send_err(c, 409, "session is changing");
|
||||
cJSON *j = wui_body(c); const cJSON *id = cJSON_GetObjectItemCaseSensitive(j, "job_id");
|
||||
const cJSON *force = cJSON_GetObjectItemCaseSensitive(j, "force");
|
||||
int rc = cJSON_IsString(id) ? cst_job_cancel(cst_agent_config(w->agent)->runtime, id->valuestring, cJSON_IsTrue(force), "user") : -1;
|
||||
cJSON_Delete(j); wui_release(w);
|
||||
if (rc) return cst_http_send_err(c, 404, "active job not found");
|
||||
return cst_http_send_str(c, 202, "application/json", "{\"ok\":true}");
|
||||
}
|
||||
|
||||
/* POST /api/extensions/trust {"on": bool}: whether .agent/plugins and
|
||||
* .agent/mcp.json of this workspace load, then reload. */
|
||||
static int h_ext_trust_x(cst_http_conn_t *c, void *ud) {
|
||||
@@ -2604,6 +2661,10 @@ int cst_webui_run(cst_agent_t *agent, const cst_webui_opts_t *opts) {
|
||||
static cst_http_route_t routes[] = {
|
||||
{"GET", "/", h_asset, NULL, 0, 0},
|
||||
{"GET", "/api/state", h_state, NULL, 0, 0},
|
||||
{"GET", "/api/task", h_task_get, NULL, 0, 0},
|
||||
{"POST", "/api/task", h_task_control, NULL, 0, 0},
|
||||
{"POST", "/api/jobs/cancel", h_job_cancel, NULL, 0, 0},
|
||||
{"POST", "/api/worktree", h_worktree, NULL, 0, 0},
|
||||
{"GET", "/api/session", h_session, NULL, 0, 0},
|
||||
{"GET", "/api/events", h_events, NULL, 0, 0},
|
||||
{"GET", "/api/sessions", h_sessions, NULL, 0, 0},
|
||||
|
||||
Reference in New Issue
Block a user