From 7994aa6c6ccbc928ae8f64692ee299e81f0a8da5 Mon Sep 17 00:00:00 2001 From: Nyk <0xnykcd@googlemail.com> Date: Sat, 21 Mar 2026 21:35:27 +0700 Subject: [PATCH] =?UTF-8?q?fix(openapi):=20burn=20down=207=20parity=20mism?= =?UTF-8?q?atches=20(66=20=E2=86=92=2059=20ignored)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add OpenAPI specs for 7 routes that the CLI/MCP server depend on: - DELETE /api/agents/{id}/memory — agent memory clear - GET /api/tokens/by-agent — per-agent cost breakdown - POST /api/tokens/rotate — API key rotation - POST /api/agents/register — agent self-registration - PATCH /api/auth/me — self-service profile update - GET /api/tasks/outcomes — task outcome analytics - GET /api/tasks/regression — regression comparison metrics Remove corresponding entries from the parity ignore list. --- openapi.json | 570 ++++++++++++++++++++++++++++- scripts/api-contract-parity.ignore | 7 - 2 files changed, 555 insertions(+), 22 deletions(-) diff --git a/openapi.json b/openapi.json index d05ec9b..fc09b0e 100644 --- a/openapi.json +++ b/openapi.json @@ -1251,6 +1251,59 @@ "$ref": "#/components/responses/NotFound" } } + }, + "delete": { + "tags": [ + "Agents" + ], + "summary": "Clear agent memory", + "operationId": "deleteAgentMemory", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "Agent ID or name" + } + ], + "responses": { + "200": { + "description": "Memory cleared", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "working_memory": { + "type": "string" + }, + "updated_at": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } } }, "/api/agents/{id}/soul": { @@ -1583,21 +1636,6 @@ } }, "responses": { - "201": { - "description": "Rule created", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "rule": { - "$ref": "#/components/schemas/AlertRule" - } - } - } - } - } - }, "200": { "description": "Rules evaluated", "content": { @@ -1636,6 +1674,21 @@ } } }, + "201": { + "description": "Rule created", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "rule": { + "$ref": "#/components/schemas/AlertRule" + } + } + } + } + } + }, "400": { "$ref": "#/components/responses/BadRequest" }, @@ -2172,6 +2225,67 @@ "$ref": "#/components/responses/Unauthorized" } } + }, + "patch": { + "tags": [ + "Auth" + ], + "summary": "Update current user profile", + "operationId": "updateCurrentUser", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "current_password": { + "type": "string" + }, + "new_password": { + "type": "string", + "minLength": 8 + }, + "display_name": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Profile updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "user": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "description": "Incorrect password or API key user" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } } }, "/api/auth/users": { @@ -8910,6 +9024,432 @@ "description": "Internal server error" } } + }, + "post": { + "tags": [ + "Admin" + ], + "summary": "Rotate API key", + "operationId": "rotateApiKey", + "responses": { + "200": { + "description": "API key rotated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "masked_key": { + "type": "string" + }, + "rotated_at": { + "type": "integer" + }, + "rotated_by": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "429": { + "description": "Rate limited" + } + } + } + }, + "/api/tokens/by-agent": { + "get": { + "tags": [ + "Tokens" + ], + "summary": "Get per-agent token cost breakdown", + "operationId": "getTokensByAgent", + "parameters": [ + { + "name": "days", + "in": "query", + "schema": { + "type": "integer", + "default": 30, + "minimum": 1, + "maximum": 365 + }, + "description": "Time window in days" + } + ], + "responses": { + "200": { + "description": "Per-agent cost breakdown", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "agents": { + "type": "array", + "items": { + "type": "object", + "properties": { + "agent": { + "type": "string" + }, + "total_input_tokens": { + "type": "integer" + }, + "total_output_tokens": { + "type": "integer" + }, + "total_tokens": { + "type": "integer" + }, + "total_cost": { + "type": "number" + }, + "session_count": { + "type": "integer" + }, + "request_count": { + "type": "integer" + }, + "last_active": { + "type": "string", + "format": "date-time" + }, + "models": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "summary": { + "type": "object", + "properties": { + "total_cost": { + "type": "number" + }, + "total_tokens": { + "type": "integer" + }, + "agent_count": { + "type": "integer" + }, + "days": { + "type": "integer" + } + } + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/api/agents/register": { + "post": { + "tags": [ + "Agents" + ], + "summary": "Agent self-registration", + "operationId": "registerAgent", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,62}$" + }, + "role": { + "type": "string", + "enum": [ + "coder", + "reviewer", + "tester", + "devops", + "researcher", + "assistant", + "agent" + ], + "default": "agent" + }, + "capabilities": { + "type": "array", + "items": { + "type": "string" + } + }, + "framework": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Agent already exists, status updated" + }, + "201": { + "description": "Agent registered", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "agent": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "role": { + "type": "string" + }, + "status": { + "type": "string" + }, + "created_at": { + "type": "integer" + } + } + }, + "registered": { + "type": "boolean" + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Invalid input" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "409": { + "description": "Agent name conflict" + }, + "429": { + "description": "Rate limited" + } + } + } + }, + "/api/tasks/outcomes": { + "get": { + "tags": [ + "Tasks" + ], + "summary": "Get task outcome analytics", + "operationId": "getTaskOutcomes", + "parameters": [ + { + "name": "timeframe", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "day", + "week", + "month", + "all" + ], + "default": "all" + }, + "description": "Time window filter" + } + ], + "responses": { + "200": { + "description": "Task outcome summary", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "timeframe": { + "type": "string" + }, + "summary": { + "type": "object", + "properties": { + "total_done": { + "type": "integer" + }, + "with_outcome": { + "type": "integer" + }, + "by_outcome": { + "type": "object" + }, + "avg_retry_count": { + "type": "number" + }, + "avg_time_to_resolution_seconds": { + "type": "number" + }, + "success_rate": { + "type": "number" + } + } + }, + "by_agent": { + "type": "object" + }, + "by_priority": { + "type": "object" + }, + "common_errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "error_message": { + "type": "string" + }, + "count": { + "type": "integer" + } + } + } + }, + "record_count": { + "type": "integer" + } + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/api/tasks/regression": { + "get": { + "tags": [ + "Tasks" + ], + "summary": "Get task regression metrics", + "operationId": "getTaskRegression", + "parameters": [ + { + "name": "beta_start", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "Cutover timestamp (unix seconds or ISO)" + }, + { + "name": "lookback_seconds", + "in": "query", + "schema": { + "type": "integer", + "default": 604800 + }, + "description": "Baseline window lookback in seconds" + } + ], + "responses": { + "200": { + "description": "Regression comparison metrics", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "metric_definitions": { + "type": "object" + }, + "params": { + "type": "object", + "properties": { + "beta_start": { + "type": "integer" + }, + "lookback_seconds": { + "type": "integer" + } + } + }, + "windows": { + "type": "object", + "properties": { + "baseline": { + "type": "object" + }, + "post": { + "type": "object" + } + } + }, + "deltas": { + "type": "object", + "properties": { + "p95_latency_seconds": { + "type": "number", + "nullable": true + }, + "intervention_rate": { + "type": "number" + } + } + } + } + } + } + } + }, + "400": { + "description": "Missing or invalid beta_start" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "429": { + "description": "Rate limited" + } + } } } }, diff --git a/scripts/api-contract-parity.ignore b/scripts/api-contract-parity.ignore index f756f79..4f9f9a5 100644 --- a/scripts/api-contract-parity.ignore +++ b/scripts/api-contract-parity.ignore @@ -1,7 +1,6 @@ # API contract parity baseline ignore list # One operation per line: METHOD /api/path # Keep this list shrinking over time; remove entries when route/spec parity is fixed. -DELETE /api/agents/{id}/memory DELETE /api/backup DELETE /api/integrations DELETE /api/memory @@ -38,12 +37,7 @@ GET /api/security-scan GET /api/spawn GET /api/super/os-users GET /api/system-monitor -GET /api/tasks/outcomes -GET /api/tasks/regression -GET /api/tokens/by-agent -PATCH /api/auth/me POST /api/agents/evals -POST /api/agents/register POST /api/auth/google/disconnect POST /api/channels POST /api/github/sync @@ -61,6 +55,5 @@ POST /api/security-scan/fix POST /api/standup POST /api/super/os-users POST /api/super/provision-jobs/{id} -POST /api/tokens/rotate PUT /api/integrations PUT /api/notifications