mirror of
https://github.com/turnstonelabs/turnstone.git
synced 2026-08-12 23:12:23 -06:00
feat(api): cycle-routed approval resolution across server, console, schemas, SDKs
POST /approve accepts cycle_id / call_id selectors and 409s on stale selectors with the current cycle's ids so clients re-render instead of silently resolving an unrelated batch. Selector-less bodies pin the resolve to the cycle the lookup returned (not "whichever is oldest by the time the resolve runs"), and Approve+Always names apply only after the pinned cycle actually resolved — the auto-approve whitelist can no longer describe a different batch than the one that resolved. approve_request carries cycle_id; approval_resolved carries cycle_id + call_ids; SSE reconnect replays every live cycle's card. The console collector, coordinator UI fan-out, and both SDKs (Python + TS) thread the cycle correlation through. BREAKING (1.7): the singular pending_approval_detail field is removed from dashboard rows, workstream detail, and node snapshots — replaced by the pending_approval_details list (one entry per live cycle, each carrying its cycle_id). stable/1.6 keeps the old shape.
This commit is contained in:
@@ -75,15 +75,25 @@ export interface ToolInfoEvent {
|
||||
items: Array<Record<string, unknown>>;
|
||||
}
|
||||
|
||||
/** One approval CYCLE awaiting the operator. Several can be outstanding
|
||||
* at once (parallel task agents each gate their own tool calls) — key
|
||||
* prompt UI by `cycle_id` and echo it back on the approve POST. */
|
||||
export interface ApproveRequestEvent {
|
||||
type: "approve_request";
|
||||
cycle_id: string;
|
||||
items: Array<Record<string, unknown>>;
|
||||
judge_pending?: boolean;
|
||||
}
|
||||
|
||||
/** A specific approval cycle resolved; `cycle_id`/`call_ids` identify
|
||||
* which prompt to dismiss. */
|
||||
export interface ApprovalResolvedEvent {
|
||||
type: "approval_resolved";
|
||||
approved: boolean;
|
||||
feedback: string;
|
||||
always?: boolean;
|
||||
cycle_id: string;
|
||||
call_ids: string[];
|
||||
}
|
||||
|
||||
export interface ToolResultEvent {
|
||||
|
||||
@@ -166,6 +166,13 @@ export class TurnstoneServer extends BaseClient {
|
||||
approved?: boolean;
|
||||
feedback?: string | null;
|
||||
always?: boolean;
|
||||
/** Resolve exactly this approval cycle (from ApproveRequestEvent.cycle_id).
|
||||
* Omitting it resolves the OLDEST live cycle — ambiguous when parallel
|
||||
* task agents have several prompts outstanding, so pass it whenever the
|
||||
* triggering event is known. */
|
||||
cycleId?: string;
|
||||
/** Alternative selector: any call_id inside the target cycle. */
|
||||
callId?: string;
|
||||
}): Promise<StatusResponse> {
|
||||
return this.request(
|
||||
"POST",
|
||||
@@ -175,6 +182,8 @@ export class TurnstoneServer extends BaseClient {
|
||||
approved: opts.approved ?? true,
|
||||
feedback: opts.feedback,
|
||||
always: opts.always,
|
||||
cycle_id: opts.cycleId,
|
||||
call_id: opts.callId,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user