Close gaps: GLM-judge (anthropic registry) + run cancel + deep-link
#2 GLM judge (closes #114): registry NamedProvider gains a `format` field; build_provider_registry builds an AnthropicProvider for format="anthropic". GLM's coding/OpenAI endpoint is ToS-throttled for raw SDK, but its Anthropic endpoint (api.z.ai/api/anthropic) accepts raw API calls (verified x-api-key -> glm-4.7), so CLAWMATES_JUDGE_MODEL=glm:glm-4.7 routes the door governor / topology judge through GLM with no runtime-routing. (Kimi-as-judge still needs a Platform key — coding key is agent-only.) #3 run-control: POST /api/topology-runs/{id}/cancel (workspace-scoped, queued/running only); the worker honors it at the step boundary (checks current_status in the checkpoint callback) and won't clobber a cancel with `failed`. Frontend Run tab gains a Cancel button and clickable recent runs that deep-link into a live/replayed stream (SSE replays from checkpoint). cm-* tests (incl. new cancel test) + clippy + frontend lint/typecheck green. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f845dfb15f
commit
6e87433c66
@@ -176,6 +176,31 @@ pub async fn fail(pool: &PgPool, id: Uuid, error: &str) -> Result<(), DbError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Cancel a run (workspace-scoped). Only `queued`/`running` jobs can be
|
||||
/// cancelled; returns whether a row transitioned. The worker observes the new
|
||||
/// status at its next step boundary and stops.
|
||||
pub async fn cancel(pool: &PgPool, id: Uuid, workspace_id: WorkspaceId) -> Result<bool, DbError> {
|
||||
let result = sqlx::query!(
|
||||
"UPDATE topology_runs
|
||||
SET status = 'cancelled', finished_at = now(), updated_at = now()
|
||||
WHERE id = $1 AND workspace_id = $2 AND status IN ('queued', 'running')",
|
||||
id,
|
||||
workspace_id.as_uuid(),
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(result.rows_affected() == 1)
|
||||
}
|
||||
|
||||
/// The current status of a run (no workspace scope) — used by the worker to
|
||||
/// detect cancellation mid-run without re-reading the whole row.
|
||||
pub async fn current_status(pool: &PgPool, id: Uuid) -> Result<Option<String>, DbError> {
|
||||
let row = sqlx::query!("SELECT status FROM topology_runs WHERE id = $1", id)
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
Ok(row.map(|r| r.status))
|
||||
}
|
||||
|
||||
/// Resume sweep: requeue `running` jobs whose worker went silent (no checkpoint
|
||||
/// touch within `older_than_secs`). The next claim resumes them from checkpoint.
|
||||
/// Returns how many were requeued.
|
||||
|
||||
Reference in New Issue
Block a user