From 55bc7f35eb8908b2fd702e8810bec1d5ae44796b Mon Sep 17 00:00:00 2001 From: Ethan Date: Wed, 22 Apr 2026 15:47:38 -0700 Subject: [PATCH] feat: declare OpenAPI response schemas for every route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every /v1 route now carries a concrete response schema in the spec instead of the permissive `z.object({}).passthrough()` placeholder. `npm run check:openapi` will now catch wire-shape drift between the formatters in memory-response-formatters.ts and the committed spec — the guardrail I flagged as missing during the snake_case wire flip. - New src/schemas/responses.ts declares Zod schemas for every emitted shape (25 top-level + internal sub-schemas): IngestResponse, SearchResponse (+ nested observability / consensus / lesson_check / tier_assignments / scope subschemas), MemoryRow / LessonRow / ClaimVersionRow / MemoryConflictRow for passthrough DB rows, HealthConfig shared by /health and /config, Consolidation (scan|execute discriminated union), Decay, Cap, LessonStats, LessonReport, Reconciliation, ReconcileStatus, ResetSource, MutationSummary, AuditTrailEntry/AuditTrail/AuditRecent, Trust / ConflictsList / ResolveConflict / AutoResolveConflicts, and the shared Success envelope. - src/schemas/openapi.ts imports those schemas and wires each route's 200 response to the right one. Error envelopes (400/404/410/500) stay as-is. - openapi.yaml + openapi.json regenerated (+3788 lines of declared response shapes). All 1037 core tests pass; check:openapi produces no diff after regen. Follow-up worth tracking: the route handlers don't yet parse their response through these schemas before sending (runtime drift detection). The spec-level check is enough to catch intentional formatter changes that forget to update the schemas; runtime parsing would catch accidental Record leaks but adds a per-request cost. Noted in tech-debt.md. Co-Authored-By: Claude Opus 4.7 (1M context) --- openapi.json | 2273 +++++++++++++++++++++++++++++++++++++- openapi.yaml | 1629 ++++++++++++++++++++++++++- src/schemas/openapi.ts | 85 +- src/schemas/responses.ts | 405 +++++++ 4 files changed, 4249 insertions(+), 143 deletions(-) create mode 100644 src/schemas/responses.ts diff --git a/openapi.json b/openapi.json index f6c8251..5ffd398 100644 --- a/openapi.json +++ b/openapi.json @@ -101,8 +101,125 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Open agent-trust conflicts for a user.", + "properties": { + "conflicts": { + "items": { + "additionalProperties": {}, + "description": "Memory conflict row from the repository.", + "properties": { + "auto_resolve_after": { + "type": [ + "string", + "null" + ] + }, + "clarification_note": { + "type": [ + "string", + "null" + ] + }, + "contradiction_confidence": { + "type": "number" + }, + "created_at": { + "type": "string" + }, + "existing_agent_id": { + "type": [ + "string", + "null" + ] + }, + "existing_memory_id": { + "type": [ + "string", + "null" + ] + }, + "existing_trust_level": { + "type": [ + "number", + "null" + ] + }, + "id": { + "type": "string" + }, + "new_agent_id": { + "type": [ + "string", + "null" + ] + }, + "new_memory_id": { + "type": [ + "string", + "null" + ] + }, + "new_trust_level": { + "type": [ + "number", + "null" + ] + }, + "resolution_policy": { + "type": [ + "string", + "null" + ] + }, + "resolved_at": { + "type": [ + "string", + "null" + ] + }, + "status": { + "enum": [ + "open", + "resolved_new", + "resolved_existing", + "resolved_both", + "auto_resolved" + ], + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "new_memory_id", + "existing_memory_id", + "new_agent_id", + "existing_agent_id", + "new_trust_level", + "existing_trust_level", + "contradiction_confidence", + "clarification_note", + "status", + "resolution_policy", + "resolved_at", + "created_at", + "auto_resolve_after" + ], + "type": "object" + }, + "type": "array" + }, + "count": { + "type": "number" + } + }, + "required": [ + "conflicts", + "count" + ], "type": "object" } } @@ -189,8 +306,15 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Count of conflicts auto-resolved in the batch pass.", + "properties": { + "resolved": { + "type": "number" + } + }, + "required": [ + "resolved" + ], "type": "object" } } @@ -291,8 +415,24 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Resolved-conflict echo.", + "properties": { + "id": { + "type": "string" + }, + "status": { + "enum": [ + "resolved_new", + "resolved_existing", + "resolved_both" + ], + "type": "string" + } + }, + "required": [ + "id", + "status" + ], "type": "object" } } @@ -382,8 +522,19 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "(userId, agentId) trust record.", + "properties": { + "agent_id": { + "type": "string" + }, + "trust_level": { + "type": "number" + } + }, + "required": [ + "agent_id", + "trust_level" + ], "type": "object" } } @@ -484,8 +635,19 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "(userId, agentId) trust record.", + "properties": { + "agent_id": { + "type": "string" + }, + "trust_level": { + "type": "number" + } + }, + "required": [ + "agent_id", + "trust_level" + ], "type": "object" } } @@ -570,8 +732,133 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Newest-first mutation rows for a user.", + "properties": { + "count": { + "type": "number" + }, + "mutations": { + "items": { + "additionalProperties": {}, + "description": "Claim-version row (one snapshot in a memory's history).", + "properties": { + "actor_model": { + "type": [ + "string", + "null" + ] + }, + "claim_id": { + "type": "string" + }, + "content": { + "type": "string" + }, + "contradiction_confidence": { + "type": [ + "number", + "null" + ] + }, + "created_at": { + "type": "string" + }, + "embedding": { + "items": { + "type": "number" + }, + "type": "array" + }, + "episode_id": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "importance": { + "type": "number" + }, + "memory_id": { + "type": [ + "string", + "null" + ] + }, + "mutation_reason": { + "type": [ + "string", + "null" + ] + }, + "mutation_type": { + "enum": [ + "add", + "update", + "supersede", + "delete", + "clarify", + null + ], + "type": [ + "string", + "null" + ] + }, + "previous_version_id": { + "type": [ + "string", + "null" + ] + }, + "source_site": { + "type": "string" + }, + "source_url": { + "type": "string" + }, + "superseded_by_version_id": { + "type": [ + "string", + "null" + ] + }, + "user_id": { + "type": "string" + }, + "valid_from": { + "type": "string" + }, + "valid_to": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "claim_id", + "user_id", + "content", + "embedding", + "importance", + "source_site", + "source_url", + "valid_from", + "created_at" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "mutations", + "count" + ], "type": "object" } } @@ -648,8 +935,34 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Aggregate mutation statistics for a user.", + "properties": { + "active_versions": { + "type": "number" + }, + "by_mutation_type": { + "additionalProperties": { + "type": "number" + }, + "type": "object" + }, + "superseded_versions": { + "type": "number" + }, + "total_claims": { + "type": "number" + }, + "total_versions": { + "type": "number" + } + }, + "required": [ + "total_versions", + "active_versions", + "superseded_versions", + "total_claims", + "by_mutation_type" + ], "type": "object" } } @@ -726,8 +1039,42 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Memory cap status and recommendation.", + "properties": { + "active_memories": { + "type": "number" + }, + "max_memories": { + "type": "number" + }, + "recommendation": { + "enum": [ + "none", + "consolidate", + "decay", + "consolidate-and-decay" + ], + "type": "string" + }, + "status": { + "enum": [ + "ok", + "warn", + "exceeded" + ], + "type": "string" + }, + "usage_ratio": { + "type": "number" + } + }, + "required": [ + "active_memories", + "max_memories", + "status", + "usage_ratio", + "recommendation" + ], "type": "object" } } @@ -807,8 +1154,83 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Applied config updates + full post-update snapshot.", + "properties": { + "applied": { + "items": { + "type": "string" + }, + "type": "array" + }, + "config": { + "description": "Runtime config snapshot returned by /health + /config.", + "properties": { + "agentic_retrieval_enabled": { + "type": "boolean" + }, + "clarification_conflict_threshold": { + "type": "number" + }, + "cross_encoder_enabled": { + "type": "boolean" + }, + "embedding_model": { + "type": "string" + }, + "embedding_provider": { + "type": "string" + }, + "entity_graph_enabled": { + "type": "boolean" + }, + "hybrid_search_enabled": { + "type": "boolean" + }, + "iterative_retrieval_enabled": { + "type": "boolean" + }, + "llm_model": { + "type": "string" + }, + "llm_provider": { + "type": "string" + }, + "max_search_results": { + "type": "number" + }, + "repair_loop_enabled": { + "type": "boolean" + }, + "retrieval_profile": { + "type": "string" + } + }, + "required": [ + "retrieval_profile", + "embedding_provider", + "embedding_model", + "llm_provider", + "llm_model", + "clarification_conflict_threshold", + "max_search_results", + "hybrid_search_enabled", + "iterative_retrieval_enabled", + "entity_graph_enabled", + "cross_encoder_enabled", + "agentic_retrieval_enabled", + "repair_loop_enabled" + ], + "type": "object" + }, + "note": { + "type": "string" + } + }, + "required": [ + "applied", + "config", + "note" + ], "type": "object" } } @@ -919,9 +1341,89 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, - "type": "object" + "anyOf": [ + { + "description": "Consolidation dry-run (execute=false).", + "properties": { + "clusters": { + "items": { + "properties": { + "avg_affinity": { + "type": "number" + }, + "member_contents": { + "items": { + "type": "string" + }, + "type": "array" + }, + "member_count": { + "type": "number" + }, + "member_ids": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "member_ids", + "member_contents", + "avg_affinity", + "member_count" + ], + "type": "object" + }, + "type": "array" + }, + "clusters_found": { + "type": "number" + }, + "memories_in_clusters": { + "type": "number" + }, + "memories_scanned": { + "type": "number" + } + }, + "required": [ + "memories_scanned", + "clusters_found", + "memories_in_clusters", + "clusters" + ], + "type": "object" + }, + { + "description": "Consolidation execution result (execute=true).", + "properties": { + "clusters_consolidated": { + "type": "number" + }, + "consolidated_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "memories_archived": { + "type": "number" + }, + "memories_created": { + "type": "number" + } + }, + "required": [ + "clusters_consolidated", + "memories_archived", + "memories_created", + "consolidated_memory_ids" + ], + "type": "object" + } + ], + "description": "Consolidation result — scan or execute." } } }, @@ -1009,8 +1511,62 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Decay evaluation (+ archive count when not dry-run).", + "properties": { + "archived": { + "type": "number" + }, + "avg_retention_score": { + "type": "number" + }, + "candidates_for_archival": { + "items": { + "properties": { + "access_count": { + "type": "number" + }, + "content": { + "type": "string" + }, + "days_since_access": { + "type": "number" + }, + "id": { + "type": "string" + }, + "importance": { + "type": "number" + }, + "retention_score": { + "type": "number" + } + }, + "required": [ + "id", + "content", + "retention_score", + "importance", + "days_since_access", + "access_count" + ], + "type": "object" + }, + "type": "array" + }, + "memories_evaluated": { + "type": "number" + }, + "retention_threshold": { + "type": "number" + } + }, + "required": [ + "memories_evaluated", + "candidates_for_archival", + "retention_threshold", + "avg_retention_score", + "archived" + ], "type": "object" } } @@ -1122,8 +1678,165 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Expanded memory rows for the requested IDs.", + "properties": { + "memories": { + "items": { + "additionalProperties": {}, + "description": "Full memory row as emitted by core.", + "properties": { + "access_count": { + "type": "number" + }, + "agent_id": { + "type": [ + "string", + "null" + ] + }, + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "deleted_at": { + "type": [ + "string", + "null" + ] + }, + "embedding": { + "items": { + "type": "number" + }, + "type": "array" + }, + "episode_id": { + "type": [ + "string", + "null" + ] + }, + "expired_at": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "importance": { + "type": "number" + }, + "keywords": { + "type": "string" + }, + "last_accessed_at": { + "type": "string" + }, + "memory_type": { + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "network": {}, + "observation_subject": { + "type": [ + "string", + "null" + ] + }, + "observed_at": { + "type": "string" + }, + "opinion_confidence": { + "type": [ + "number", + "null" + ] + }, + "overview": { + "type": "string" + }, + "source_site": { + "type": "string" + }, + "source_url": { + "type": "string" + }, + "status": { + "enum": [ + "active", + "needs_clarification" + ], + "type": "string" + }, + "summary": { + "type": "string" + }, + "trust_score": { + "type": "number" + }, + "user_id": { + "type": "string" + }, + "visibility": { + "enum": [ + "agent_only", + "restricted", + "workspace", + null + ], + "type": [ + "string", + "null" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "content", + "embedding", + "memory_type", + "importance", + "source_site", + "source_url", + "status", + "metadata", + "keywords", + "summary", + "overview", + "trust_score", + "observed_at", + "created_at", + "last_accessed_at", + "access_count" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "memories" + ], "type": "object" } } @@ -1189,8 +1902,79 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Health + runtime config snapshot.", + "properties": { + "config": { + "description": "Runtime config snapshot returned by /health + /config.", + "properties": { + "agentic_retrieval_enabled": { + "type": "boolean" + }, + "clarification_conflict_threshold": { + "type": "number" + }, + "cross_encoder_enabled": { + "type": "boolean" + }, + "embedding_model": { + "type": "string" + }, + "embedding_provider": { + "type": "string" + }, + "entity_graph_enabled": { + "type": "boolean" + }, + "hybrid_search_enabled": { + "type": "boolean" + }, + "iterative_retrieval_enabled": { + "type": "boolean" + }, + "llm_model": { + "type": "string" + }, + "llm_provider": { + "type": "string" + }, + "max_search_results": { + "type": "number" + }, + "repair_loop_enabled": { + "type": "boolean" + }, + "retrieval_profile": { + "type": "string" + } + }, + "required": [ + "retrieval_profile", + "embedding_provider", + "embedding_model", + "llm_provider", + "llm_model", + "clarification_conflict_threshold", + "max_search_results", + "hybrid_search_enabled", + "iterative_retrieval_enabled", + "entity_graph_enabled", + "cross_encoder_enabled", + "agentic_retrieval_enabled", + "repair_loop_enabled" + ], + "type": "object" + }, + "status": { + "enum": [ + "ok" + ], + "type": "string" + } + }, + "required": [ + "status", + "config" + ], "type": "object" } } @@ -1268,8 +2052,57 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Ingest result: extraction counts + stored/updated memory IDs.", + "properties": { + "composites_created": { + "type": "number" + }, + "episode_id": { + "type": "string" + }, + "facts_extracted": { + "type": "number" + }, + "links_created": { + "type": "number" + }, + "memories_deleted": { + "type": "number" + }, + "memories_skipped": { + "type": "number" + }, + "memories_stored": { + "type": "number" + }, + "memories_updated": { + "type": "number" + }, + "stored_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "updated_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "episode_id", + "facts_extracted", + "memories_stored", + "memories_updated", + "memories_deleted", + "memories_skipped", + "stored_memory_ids", + "updated_memory_ids", + "links_created", + "composites_created" + ], "type": "object" } } @@ -1391,8 +2224,57 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Ingest result: extraction counts + stored/updated memory IDs.", + "properties": { + "composites_created": { + "type": "number" + }, + "episode_id": { + "type": "string" + }, + "facts_extracted": { + "type": "number" + }, + "links_created": { + "type": "number" + }, + "memories_deleted": { + "type": "number" + }, + "memories_skipped": { + "type": "number" + }, + "memories_stored": { + "type": "number" + }, + "memories_updated": { + "type": "number" + }, + "stored_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "updated_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "episode_id", + "facts_extracted", + "memories_stored", + "memories_updated", + "memories_deleted", + "memories_skipped", + "stored_memory_ids", + "updated_memory_ids", + "links_created", + "composites_created" + ], "type": "object" } } @@ -1469,8 +2351,96 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Active lessons for a user.", + "properties": { + "count": { + "type": "number" + }, + "lessons": { + "items": { + "additionalProperties": {}, + "description": "Lesson row from the repository.", + "properties": { + "active": { + "type": "boolean" + }, + "created_at": { + "type": "string" + }, + "embedding": { + "items": { + "type": "number" + }, + "type": "array" + }, + "id": { + "type": "string" + }, + "lesson_type": { + "enum": [ + "injection_blocked", + "false_memory", + "contradiction_pattern", + "user_reported", + "consensus_violation", + "trust_violation" + ], + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "pattern": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "source_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "source_query": { + "type": [ + "string", + "null" + ] + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "id", + "user_id", + "lesson_type", + "pattern", + "embedding", + "source_memory_ids", + "source_query", + "severity", + "active", + "metadata", + "created_at" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "lessons", + "count" + ], "type": "object" } } @@ -1569,8 +2539,15 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "ID of the newly-reported lesson.", + "properties": { + "lesson_id": { + "type": "string" + } + }, + "required": [ + "lesson_id" + ], "type": "object" } } @@ -1647,8 +2624,22 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Aggregate lesson counts by type.", + "properties": { + "by_type": { + "additionalProperties": { + "type": "number" + }, + "type": "object" + }, + "total_active": { + "type": "number" + } + }, + "required": [ + "total_active", + "by_type" + ], "type": "object" } } @@ -1734,8 +2725,18 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Successful no-payload operation.", + "properties": { + "success": { + "enum": [ + true + ], + "type": "boolean" + } + }, + "required": [ + "success" + ], "type": "object" } } @@ -1862,8 +2863,169 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Paginated memory list.", + "properties": { + "count": { + "type": "number" + }, + "memories": { + "items": { + "additionalProperties": {}, + "description": "Full memory row as emitted by core.", + "properties": { + "access_count": { + "type": "number" + }, + "agent_id": { + "type": [ + "string", + "null" + ] + }, + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "deleted_at": { + "type": [ + "string", + "null" + ] + }, + "embedding": { + "items": { + "type": "number" + }, + "type": "array" + }, + "episode_id": { + "type": [ + "string", + "null" + ] + }, + "expired_at": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "importance": { + "type": "number" + }, + "keywords": { + "type": "string" + }, + "last_accessed_at": { + "type": "string" + }, + "memory_type": { + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "network": {}, + "observation_subject": { + "type": [ + "string", + "null" + ] + }, + "observed_at": { + "type": "string" + }, + "opinion_confidence": { + "type": [ + "number", + "null" + ] + }, + "overview": { + "type": "string" + }, + "source_site": { + "type": "string" + }, + "source_url": { + "type": "string" + }, + "status": { + "enum": [ + "active", + "needs_clarification" + ], + "type": "string" + }, + "summary": { + "type": "string" + }, + "trust_score": { + "type": "number" + }, + "user_id": { + "type": "string" + }, + "visibility": { + "enum": [ + "agent_only", + "restricted", + "workspace", + null + ], + "type": [ + "string", + "null" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "content", + "embedding", + "memory_type", + "importance", + "source_site", + "source_url", + "status", + "metadata", + "keywords", + "summary", + "overview", + "trust_score", + "observed_at", + "created_at", + "last_accessed_at", + "access_count" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "memories", + "count" + ], "type": "object" } } @@ -1944,8 +3106,47 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Deferred-AUDN reconciliation counters.", + "properties": { + "adds": { + "type": "number" + }, + "deletes": { + "type": "number" + }, + "duration_ms": { + "type": "number" + }, + "errors": { + "type": "number" + }, + "noops": { + "type": "number" + }, + "processed": { + "type": "number" + }, + "resolved": { + "type": "number" + }, + "supersedes": { + "type": "number" + }, + "updates": { + "type": "number" + } + }, + "required": [ + "processed", + "resolved", + "noops", + "updates", + "supersedes", + "deletes", + "adds", + "errors", + "duration_ms" + ], "type": "object" } } @@ -2023,7 +3224,19 @@ "application/json": { "schema": { "additionalProperties": {}, - "properties": {}, + "description": "Current deferred-AUDN queue state.", + "properties": { + "enabled": { + "type": "boolean" + }, + "pending": { + "type": "number" + } + }, + "required": [ + "pending", + "enabled" + ], "type": "object" } } @@ -2115,8 +3328,26 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Reset-by-source deletion counts.", + "properties": { + "deleted_episodes": { + "type": "number" + }, + "deleted_memories": { + "type": "number" + }, + "success": { + "enum": [ + true + ], + "type": "boolean" + } + }, + "required": [ + "success", + "deleted_memories", + "deleted_episodes" + ], "type": "object" } } @@ -2274,8 +3505,334 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Search results with injection_text, citations, and optional traces.", + "properties": { + "citations": { + "items": { + "type": "string" + }, + "type": "array" + }, + "consensus": { + "properties": { + "filtered_count": { + "type": "number" + }, + "original_count": { + "type": "number" + }, + "removed_count": { + "type": "number" + }, + "removed_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "original_count", + "filtered_count", + "removed_count", + "removed_memory_ids" + ], + "type": "object" + }, + "count": { + "type": "number" + }, + "estimated_context_tokens": { + "type": "number" + }, + "expand_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "injection_text": { + "type": "string" + }, + "lesson_check": { + "properties": { + "highest_severity": { + "type": "string" + }, + "matched_count": { + "type": "number" + }, + "safe": { + "type": "boolean" + }, + "warnings": { + "items": {}, + "type": "array" + } + }, + "required": [ + "safe", + "warnings", + "highest_severity", + "matched_count" + ], + "type": "object" + }, + "memories": { + "items": { + "description": "Projected memory record in a search result.", + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "id": { + "type": "string" + }, + "importance": { + "type": "number" + }, + "score": { + "type": "number" + }, + "similarity": { + "type": "number" + }, + "source_site": { + "type": "string" + } + }, + "required": [ + "id", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "observability": { + "description": "Retrieval pipeline trace summaries.", + "properties": { + "assembly": { + "properties": { + "blocks": { + "items": { + "type": "string" + }, + "type": "array" + }, + "final_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "final_token_cost": { + "type": "number" + }, + "primary_evidence_position": { + "type": [ + "number", + "null" + ] + }, + "token_budget": { + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "final_ids", + "final_token_cost", + "token_budget", + "primary_evidence_position", + "blocks" + ], + "type": "object" + }, + "packaging": { + "properties": { + "date_count": { + "type": "number" + }, + "dropped_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "episode_count": { + "type": "number" + }, + "evidence_roles": { + "additionalProperties": { + "enum": [ + "primary", + "supporting", + "historical", + "contextual" + ], + "type": "string" + }, + "type": "object" + }, + "has_conflict_block": { + "type": "boolean" + }, + "has_current_marker": { + "type": "boolean" + }, + "included_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "package_type": { + "enum": [ + "subject-pack", + "timeline-pack", + "tiered" + ], + "type": "string" + }, + "token_cost": { + "type": "number" + } + }, + "required": [ + "package_type", + "included_ids", + "dropped_ids", + "evidence_roles", + "episode_count", + "date_count", + "has_current_marker", + "has_conflict_block", + "token_cost" + ], + "type": "object" + }, + "retrieval": { + "properties": { + "candidate_count": { + "type": "number" + }, + "candidate_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "query_text": { + "type": "string" + }, + "skip_repair": { + "type": "boolean" + } + }, + "required": [ + "candidate_ids", + "candidate_count", + "query_text", + "skip_repair" + ], + "type": "object" + } + }, + "type": "object" + }, + "retrieval_mode": { + "enum": [ + "flat", + "tiered", + "abstract-aware" + ], + "type": "string" + }, + "scope": { + "anyOf": [ + { + "properties": { + "kind": { + "enum": [ + "user" + ], + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "kind", + "user_id" + ], + "type": "object" + }, + { + "properties": { + "agent_id": { + "type": "string" + }, + "agent_scope": {}, + "kind": { + "enum": [ + "workspace" + ], + "type": "string" + }, + "user_id": { + "type": "string" + }, + "workspace_id": { + "type": "string" + } + }, + "required": [ + "kind", + "user_id", + "workspace_id", + "agent_id" + ], + "type": "object" + } + ], + "description": "Echoed scope: user-scoped or workspace-scoped." + }, + "tier_assignments": { + "items": { + "properties": { + "estimated_tokens": { + "type": "number" + }, + "memory_id": { + "type": "string" + }, + "tier": { + "type": "string" + } + }, + "required": [ + "memory_id", + "tier", + "estimated_tokens" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "count", + "retrieval_mode", + "scope", + "memories" + ], "type": "object" } } @@ -2433,8 +3990,334 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Search results with injection_text, citations, and optional traces.", + "properties": { + "citations": { + "items": { + "type": "string" + }, + "type": "array" + }, + "consensus": { + "properties": { + "filtered_count": { + "type": "number" + }, + "original_count": { + "type": "number" + }, + "removed_count": { + "type": "number" + }, + "removed_memory_ids": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "original_count", + "filtered_count", + "removed_count", + "removed_memory_ids" + ], + "type": "object" + }, + "count": { + "type": "number" + }, + "estimated_context_tokens": { + "type": "number" + }, + "expand_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "injection_text": { + "type": "string" + }, + "lesson_check": { + "properties": { + "highest_severity": { + "type": "string" + }, + "matched_count": { + "type": "number" + }, + "safe": { + "type": "boolean" + }, + "warnings": { + "items": {}, + "type": "array" + } + }, + "required": [ + "safe", + "warnings", + "highest_severity", + "matched_count" + ], + "type": "object" + }, + "memories": { + "items": { + "description": "Projected memory record in a search result.", + "properties": { + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "id": { + "type": "string" + }, + "importance": { + "type": "number" + }, + "score": { + "type": "number" + }, + "similarity": { + "type": "number" + }, + "source_site": { + "type": "string" + } + }, + "required": [ + "id", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "observability": { + "description": "Retrieval pipeline trace summaries.", + "properties": { + "assembly": { + "properties": { + "blocks": { + "items": { + "type": "string" + }, + "type": "array" + }, + "final_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "final_token_cost": { + "type": "number" + }, + "primary_evidence_position": { + "type": [ + "number", + "null" + ] + }, + "token_budget": { + "type": [ + "number", + "null" + ] + } + }, + "required": [ + "final_ids", + "final_token_cost", + "token_budget", + "primary_evidence_position", + "blocks" + ], + "type": "object" + }, + "packaging": { + "properties": { + "date_count": { + "type": "number" + }, + "dropped_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "episode_count": { + "type": "number" + }, + "evidence_roles": { + "additionalProperties": { + "enum": [ + "primary", + "supporting", + "historical", + "contextual" + ], + "type": "string" + }, + "type": "object" + }, + "has_conflict_block": { + "type": "boolean" + }, + "has_current_marker": { + "type": "boolean" + }, + "included_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "package_type": { + "enum": [ + "subject-pack", + "timeline-pack", + "tiered" + ], + "type": "string" + }, + "token_cost": { + "type": "number" + } + }, + "required": [ + "package_type", + "included_ids", + "dropped_ids", + "evidence_roles", + "episode_count", + "date_count", + "has_current_marker", + "has_conflict_block", + "token_cost" + ], + "type": "object" + }, + "retrieval": { + "properties": { + "candidate_count": { + "type": "number" + }, + "candidate_ids": { + "items": { + "type": "string" + }, + "type": "array" + }, + "query_text": { + "type": "string" + }, + "skip_repair": { + "type": "boolean" + } + }, + "required": [ + "candidate_ids", + "candidate_count", + "query_text", + "skip_repair" + ], + "type": "object" + } + }, + "type": "object" + }, + "retrieval_mode": { + "enum": [ + "flat", + "tiered", + "abstract-aware" + ], + "type": "string" + }, + "scope": { + "anyOf": [ + { + "properties": { + "kind": { + "enum": [ + "user" + ], + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "required": [ + "kind", + "user_id" + ], + "type": "object" + }, + { + "properties": { + "agent_id": { + "type": "string" + }, + "agent_scope": {}, + "kind": { + "enum": [ + "workspace" + ], + "type": "string" + }, + "user_id": { + "type": "string" + }, + "workspace_id": { + "type": "string" + } + }, + "required": [ + "kind", + "user_id", + "workspace_id", + "agent_id" + ], + "type": "object" + } + ], + "description": "Echoed scope: user-scoped or workspace-scoped." + }, + "tier_assignments": { + "items": { + "properties": { + "estimated_tokens": { + "type": "number" + }, + "memory_id": { + "type": "string" + }, + "tier": { + "type": "string" + } + }, + "required": [ + "memory_id", + "tier", + "estimated_tokens" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "count", + "retrieval_mode", + "scope", + "memories" + ], "type": "object" } } @@ -2511,8 +4394,26 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Aggregate memory stats for a user.", + "properties": { + "avg_importance": { + "type": "number" + }, + "count": { + "type": "number" + }, + "source_distribution": { + "additionalProperties": { + "type": "number" + }, + "type": "object" + } + }, + "required": [ + "count", + "avg_importance", + "source_distribution" + ], "type": "object" } } @@ -2615,8 +4516,18 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Successful no-payload operation.", + "properties": { + "success": { + "enum": [ + true + ], + "type": "boolean" + } + }, + "required": [ + "success" + ], "type": "object" } } @@ -2740,7 +4651,152 @@ "application/json": { "schema": { "additionalProperties": {}, - "properties": {}, + "description": "Full memory row as emitted by core.", + "properties": { + "access_count": { + "type": "number" + }, + "agent_id": { + "type": [ + "string", + "null" + ] + }, + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "deleted_at": { + "type": [ + "string", + "null" + ] + }, + "embedding": { + "items": { + "type": "number" + }, + "type": "array" + }, + "episode_id": { + "type": [ + "string", + "null" + ] + }, + "expired_at": { + "type": [ + "string", + "null" + ] + }, + "id": { + "type": "string" + }, + "importance": { + "type": "number" + }, + "keywords": { + "type": "string" + }, + "last_accessed_at": { + "type": "string" + }, + "memory_type": { + "type": "string" + }, + "metadata": { + "additionalProperties": {}, + "type": "object" + }, + "namespace": { + "type": [ + "string", + "null" + ] + }, + "network": {}, + "observation_subject": { + "type": [ + "string", + "null" + ] + }, + "observed_at": { + "type": "string" + }, + "opinion_confidence": { + "type": [ + "number", + "null" + ] + }, + "overview": { + "type": "string" + }, + "source_site": { + "type": "string" + }, + "source_url": { + "type": "string" + }, + "status": { + "enum": [ + "active", + "needs_clarification" + ], + "type": "string" + }, + "summary": { + "type": "string" + }, + "trust_score": { + "type": "number" + }, + "user_id": { + "type": "string" + }, + "visibility": { + "enum": [ + "agent_only", + "restricted", + "workspace", + null + ], + "type": [ + "string", + "null" + ] + }, + "workspace_id": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "user_id", + "content", + "embedding", + "memory_type", + "importance", + "source_site", + "source_url", + "status", + "metadata", + "keywords", + "summary", + "overview", + "trust_score", + "observed_at", + "created_at", + "last_accessed_at", + "access_count" + ], "type": "object" } } @@ -2848,8 +4904,111 @@ "content": { "application/json": { "schema": { - "additionalProperties": {}, - "properties": {}, + "description": "Full version trail for a single memory.", + "properties": { + "memory_id": { + "type": "string" + }, + "trail": { + "items": { + "description": "Single entry in a memory's audit trail.", + "properties": { + "actor_model": { + "type": [ + "string", + "null" + ] + }, + "claim_id": { + "type": "string" + }, + "content": { + "type": "string" + }, + "contradiction_confidence": { + "type": [ + "number", + "null" + ] + }, + "memory_id": { + "type": [ + "string", + "null" + ] + }, + "mutation_reason": { + "type": [ + "string", + "null" + ] + }, + "mutation_type": { + "enum": [ + "add", + "update", + "supersede", + "delete", + "clarify", + null + ], + "type": [ + "string", + "null" + ] + }, + "previous_version_id": { + "type": [ + "string", + "null" + ] + }, + "superseded_by_version_id": { + "type": [ + "string", + "null" + ] + }, + "valid_from": { + "type": "string" + }, + "valid_to": { + "type": [ + "string", + "null" + ] + }, + "version_id": { + "type": "string" + } + }, + "required": [ + "version_id", + "claim_id", + "content", + "mutation_type", + "mutation_reason", + "actor_model", + "contradiction_confidence", + "previous_version_id", + "superseded_by_version_id", + "valid_from", + "valid_to", + "memory_id" + ], + "type": "object" + }, + "type": "array" + }, + "version_count": { + "type": "number" + } + }, + "required": [ + "memory_id", + "trail", + "version_count" + ], "type": "object" } } diff --git a/openapi.yaml b/openapi.yaml index 5a61d71..64e693f 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -72,8 +72,92 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Open agent-trust conflicts for a user. + properties: + conflicts: + items: + additionalProperties: {} + description: Memory conflict row from the repository. + properties: + auto_resolve_after: + type: + - string + - "null" + clarification_note: + type: + - string + - "null" + contradiction_confidence: + type: number + created_at: + type: string + existing_agent_id: + type: + - string + - "null" + existing_memory_id: + type: + - string + - "null" + existing_trust_level: + type: + - number + - "null" + id: + type: string + new_agent_id: + type: + - string + - "null" + new_memory_id: + type: + - string + - "null" + new_trust_level: + type: + - number + - "null" + resolution_policy: + type: + - string + - "null" + resolved_at: + type: + - string + - "null" + status: + enum: + - open + - resolved_new + - resolved_existing + - resolved_both + - auto_resolved + type: string + user_id: + type: string + required: + - id + - user_id + - new_memory_id + - existing_memory_id + - new_agent_id + - existing_agent_id + - new_trust_level + - existing_trust_level + - contradiction_confidence + - clarification_note + - status + - resolution_policy + - resolved_at + - created_at + - auto_resolve_after + type: object + type: array + count: + type: number + required: + - conflicts + - count type: object description: Conflicts list. "400": @@ -129,8 +213,12 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Count of conflicts auto-resolved in the batch pass. + properties: + resolved: + type: number + required: + - resolved type: object description: Count of resolved conflicts. "400": @@ -195,8 +283,19 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Resolved-conflict echo. + properties: + id: + type: string + status: + enum: + - resolved_new + - resolved_existing + - resolved_both + type: string + required: + - id + - status type: object description: Resolution confirmation. "400": @@ -255,8 +354,15 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: (userId, agentId) trust record. + properties: + agent_id: + type: string + trust_level: + type: number + required: + - agent_id + - trust_level type: object description: Agent id + trust level. "400": @@ -324,8 +430,15 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: (userId, agentId) trust record. + properties: + agent_id: + type: string + trust_level: + type: number + required: + - agent_id + - trust_level type: object description: Agent id + applied trust level. "400": @@ -379,8 +492,96 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Newest-first mutation rows for a user. + properties: + count: + type: number + mutations: + items: + additionalProperties: {} + description: Claim-version row (one snapshot in a memory's history). + properties: + actor_model: + type: + - string + - "null" + claim_id: + type: string + content: + type: string + contradiction_confidence: + type: + - number + - "null" + created_at: + type: string + embedding: + items: + type: number + type: array + episode_id: + type: + - string + - "null" + id: + type: string + importance: + type: number + memory_id: + type: + - string + - "null" + mutation_reason: + type: + - string + - "null" + mutation_type: + enum: + - add + - update + - supersede + - delete + - clarify + - null + type: + - string + - "null" + previous_version_id: + type: + - string + - "null" + source_site: + type: string + source_url: + type: string + superseded_by_version_id: + type: + - string + - "null" + user_id: + type: string + valid_from: + type: string + valid_to: + type: + - string + - "null" + required: + - id + - claim_id + - user_id + - content + - embedding + - importance + - source_site + - source_url + - valid_from + - created_at + type: object + type: array + required: + - mutations + - count type: object description: Recent mutations. "400": @@ -429,8 +630,26 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Aggregate mutation statistics for a user. + properties: + active_versions: + type: number + by_mutation_type: + additionalProperties: + type: number + type: object + superseded_versions: + type: number + total_claims: + type: number + total_versions: + type: number + required: + - total_versions + - active_versions + - superseded_versions + - total_claims + - by_mutation_type type: object description: Mutation summary. "400": @@ -479,8 +698,33 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Memory cap status and recommendation. + properties: + active_memories: + type: number + max_memories: + type: number + recommendation: + enum: + - none + - consolidate + - decay + - consolidate-and-decay + type: string + status: + enum: + - ok + - warn + - exceeded + type: string + usage_ratio: + type: number + required: + - active_memories + - max_memories + - status + - usage_ratio + - recommendation type: object description: Cap status. "400": @@ -532,8 +776,62 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Applied config updates + full post-update snapshot. + properties: + applied: + items: + type: string + type: array + config: + description: Runtime config snapshot returned by /health + /config. + properties: + agentic_retrieval_enabled: + type: boolean + clarification_conflict_threshold: + type: number + cross_encoder_enabled: + type: boolean + embedding_model: + type: string + embedding_provider: + type: string + entity_graph_enabled: + type: boolean + hybrid_search_enabled: + type: boolean + iterative_retrieval_enabled: + type: boolean + llm_model: + type: string + llm_provider: + type: string + max_search_results: + type: number + repair_loop_enabled: + type: boolean + retrieval_profile: + type: string + required: + - retrieval_profile + - embedding_provider + - embedding_model + - llm_provider + - llm_model + - clarification_conflict_threshold + - max_search_results + - hybrid_search_enabled + - iterative_retrieval_enabled + - entity_graph_enabled + - cross_encoder_enabled + - agentic_retrieval_enabled + - repair_loop_enabled + type: object + note: + type: string + required: + - applied + - config + - note type: object description: Applied changes + config snapshot. "400": @@ -602,9 +900,62 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} - type: object + anyOf: + - description: Consolidation dry-run (execute=false). + properties: + clusters: + items: + properties: + avg_affinity: + type: number + member_contents: + items: + type: string + type: array + member_count: + type: number + member_ids: + items: + type: string + type: array + required: + - member_ids + - member_contents + - avg_affinity + - member_count + type: object + type: array + clusters_found: + type: number + memories_in_clusters: + type: number + memories_scanned: + type: number + required: + - memories_scanned + - clusters_found + - memories_in_clusters + - clusters + type: object + - description: Consolidation execution result (execute=true). + properties: + clusters_consolidated: + type: number + consolidated_memory_ids: + items: + type: string + type: array + memories_archived: + type: number + memories_created: + type: number + required: + - clusters_consolidated + - memories_archived + - memories_created + - consolidated_memory_ids + type: object + description: Consolidation result — scan or execute. description: Consolidation result. "400": content: @@ -660,8 +1011,46 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Decay evaluation (+ archive count when not dry-run). + properties: + archived: + type: number + avg_retention_score: + type: number + candidates_for_archival: + items: + properties: + access_count: + type: number + content: + type: string + days_since_access: + type: number + id: + type: string + importance: + type: number + retention_score: + type: number + required: + - id + - content + - retention_score + - importance + - days_since_access + - access_count + type: object + type: array + memories_evaluated: + type: number + retention_threshold: + type: number + required: + - memories_evaluated + - candidates_for_archival + - retention_threshold + - avg_retention_score + - archived type: object description: Decay evaluation + archived count. "400": @@ -736,8 +1125,120 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Expanded memory rows for the requested IDs. + properties: + memories: + items: + additionalProperties: {} + description: Full memory row as emitted by core. + properties: + access_count: + type: number + agent_id: + type: + - string + - "null" + content: + type: string + created_at: + type: string + deleted_at: + type: + - string + - "null" + embedding: + items: + type: number + type: array + episode_id: + type: + - string + - "null" + expired_at: + type: + - string + - "null" + id: + type: string + importance: + type: number + keywords: + type: string + last_accessed_at: + type: string + memory_type: + type: string + metadata: + additionalProperties: {} + type: object + namespace: + type: + - string + - "null" + network: {} + observation_subject: + type: + - string + - "null" + observed_at: + type: string + opinion_confidence: + type: + - number + - "null" + overview: + type: string + source_site: + type: string + source_url: + type: string + status: + enum: + - active + - needs_clarification + type: string + summary: + type: string + trust_score: + type: number + user_id: + type: string + visibility: + enum: + - agent_only + - restricted + - workspace + - null + type: + - string + - "null" + workspace_id: + type: + - string + - "null" + required: + - id + - user_id + - content + - embedding + - memory_type + - importance + - source_site + - source_url + - status + - metadata + - keywords + - summary + - overview + - trust_score + - observed_at + - created_at + - last_accessed_at + - access_count + type: object + type: array + required: + - memories type: object description: Expanded memories array. "400": @@ -779,8 +1280,59 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Health + runtime config snapshot. + properties: + config: + description: Runtime config snapshot returned by /health + /config. + properties: + agentic_retrieval_enabled: + type: boolean + clarification_conflict_threshold: + type: number + cross_encoder_enabled: + type: boolean + embedding_model: + type: string + embedding_provider: + type: string + entity_graph_enabled: + type: boolean + hybrid_search_enabled: + type: boolean + iterative_retrieval_enabled: + type: boolean + llm_model: + type: string + llm_provider: + type: string + max_search_results: + type: number + repair_loop_enabled: + type: boolean + retrieval_profile: + type: string + required: + - retrieval_profile + - embedding_provider + - embedding_model + - llm_provider + - llm_model + - clarification_conflict_threshold + - max_search_results + - hybrid_search_enabled + - iterative_retrieval_enabled + - entity_graph_enabled + - cross_encoder_enabled + - agentic_retrieval_enabled + - repair_loop_enabled + type: object + status: + enum: + - ok + type: string + required: + - status + - config type: object description: Status + config snapshot. summary: Subsystem liveness + current runtime config snapshot. @@ -835,8 +1387,43 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: "Ingest result: extraction counts + stored/updated memory IDs." + properties: + composites_created: + type: number + episode_id: + type: string + facts_extracted: + type: number + links_created: + type: number + memories_deleted: + type: number + memories_skipped: + type: number + memories_stored: + type: number + memories_updated: + type: number + stored_memory_ids: + items: + type: string + type: array + updated_memory_ids: + items: + type: string + type: array + required: + - episode_id + - facts_extracted + - memories_stored + - memories_updated + - memories_deleted + - memories_skipped + - stored_memory_ids + - updated_memory_ids + - links_created + - composites_created type: object description: Ingest result with extracted facts. "400": @@ -919,8 +1506,43 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: "Ingest result: extraction counts + stored/updated memory IDs." + properties: + composites_created: + type: number + episode_id: + type: string + facts_extracted: + type: number + links_created: + type: number + memories_deleted: + type: number + memories_skipped: + type: number + memories_stored: + type: number + memories_updated: + type: number + stored_memory_ids: + items: + type: string + type: array + updated_memory_ids: + items: + type: string + type: array + required: + - episode_id + - facts_extracted + - memories_stored + - memories_updated + - memories_deleted + - memories_skipped + - stored_memory_ids + - updated_memory_ids + - links_created + - composites_created type: object description: Ingest result. "400": @@ -969,8 +1591,73 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Active lessons for a user. + properties: + count: + type: number + lessons: + items: + additionalProperties: {} + description: Lesson row from the repository. + properties: + active: + type: boolean + created_at: + type: string + embedding: + items: + type: number + type: array + id: + type: string + lesson_type: + enum: + - injection_blocked + - false_memory + - contradiction_pattern + - user_reported + - consensus_violation + - trust_violation + type: string + metadata: + additionalProperties: {} + type: object + pattern: + type: string + severity: + enum: + - low + - medium + - high + - critical + type: string + source_memory_ids: + items: + type: string + type: array + source_query: + type: + - string + - "null" + user_id: + type: string + required: + - id + - user_id + - lesson_type + - pattern + - embedding + - source_memory_ids + - source_query + - severity + - active + - metadata + - created_at + type: object + type: array + required: + - lessons + - count type: object description: Lessons list. "400": @@ -1035,8 +1722,12 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: ID of the newly-reported lesson. + properties: + lesson_id: + type: string + required: + - lesson_id type: object description: Lesson id. "400": @@ -1085,8 +1776,17 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Aggregate lesson counts by type. + properties: + by_type: + additionalProperties: + type: number + type: object + total_active: + type: number + required: + - total_active + - by_type type: object description: Stats. "400": @@ -1141,8 +1841,14 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Successful no-payload operation. + properties: + success: + enum: + - true + type: boolean + required: + - success type: object description: Success. "400": @@ -1223,8 +1929,123 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Paginated memory list. + properties: + count: + type: number + memories: + items: + additionalProperties: {} + description: Full memory row as emitted by core. + properties: + access_count: + type: number + agent_id: + type: + - string + - "null" + content: + type: string + created_at: + type: string + deleted_at: + type: + - string + - "null" + embedding: + items: + type: number + type: array + episode_id: + type: + - string + - "null" + expired_at: + type: + - string + - "null" + id: + type: string + importance: + type: number + keywords: + type: string + last_accessed_at: + type: string + memory_type: + type: string + metadata: + additionalProperties: {} + type: object + namespace: + type: + - string + - "null" + network: {} + observation_subject: + type: + - string + - "null" + observed_at: + type: string + opinion_confidence: + type: + - number + - "null" + overview: + type: string + source_site: + type: string + source_url: + type: string + status: + enum: + - active + - needs_clarification + type: string + summary: + type: string + trust_score: + type: number + user_id: + type: string + visibility: + enum: + - agent_only + - restricted + - workspace + - null + type: + - string + - "null" + workspace_id: + type: + - string + - "null" + required: + - id + - user_id + - content + - embedding + - memory_type + - importance + - source_site + - source_url + - status + - metadata + - keywords + - summary + - overview + - trust_score + - observed_at + - created_at + - last_accessed_at + - access_count + type: object + type: array + required: + - memories + - count type: object description: Paginated memory list. "400": @@ -1275,8 +2096,36 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Deferred-AUDN reconciliation counters. + properties: + adds: + type: number + deletes: + type: number + duration_ms: + type: number + errors: + type: number + noops: + type: number + processed: + type: number + resolved: + type: number + supersedes: + type: number + updates: + type: number + required: + - processed + - resolved + - noops + - updates + - supersedes + - deletes + - adds + - errors + - duration_ms type: object description: Reconciliation result. "400": @@ -1326,7 +2175,15 @@ paths: application/json: schema: additionalProperties: {} - properties: {} + description: Current deferred-AUDN queue state. + properties: + enabled: + type: boolean + pending: + type: number + required: + - pending + - enabled type: object description: Status payload. "400": @@ -1386,8 +2243,20 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Reset-by-source deletion counts. + properties: + deleted_episodes: + type: number + deleted_memories: + type: number + success: + enum: + - true + type: boolean + required: + - success + - deleted_memories + - deleted_episodes type: object description: Reset result. "400": @@ -1494,8 +2363,233 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Search results with injection_text, citations, and optional traces. + properties: + citations: + items: + type: string + type: array + consensus: + properties: + filtered_count: + type: number + original_count: + type: number + removed_count: + type: number + removed_memory_ids: + items: + type: string + type: array + required: + - original_count + - filtered_count + - removed_count + - removed_memory_ids + type: object + count: + type: number + estimated_context_tokens: + type: number + expand_ids: + items: + type: string + type: array + injection_text: + type: string + lesson_check: + properties: + highest_severity: + type: string + matched_count: + type: number + safe: + type: boolean + warnings: + items: {} + type: array + required: + - safe + - warnings + - highest_severity + - matched_count + type: object + memories: + items: + description: Projected memory record in a search result. + properties: + content: + type: string + created_at: + type: string + id: + type: string + importance: + type: number + score: + type: number + similarity: + type: number + source_site: + type: string + required: + - id + - content + type: object + type: array + observability: + description: Retrieval pipeline trace summaries. + properties: + assembly: + properties: + blocks: + items: + type: string + type: array + final_ids: + items: + type: string + type: array + final_token_cost: + type: number + primary_evidence_position: + type: + - number + - "null" + token_budget: + type: + - number + - "null" + required: + - final_ids + - final_token_cost + - token_budget + - primary_evidence_position + - blocks + type: object + packaging: + properties: + date_count: + type: number + dropped_ids: + items: + type: string + type: array + episode_count: + type: number + evidence_roles: + additionalProperties: + enum: + - primary + - supporting + - historical + - contextual + type: string + type: object + has_conflict_block: + type: boolean + has_current_marker: + type: boolean + included_ids: + items: + type: string + type: array + package_type: + enum: + - subject-pack + - timeline-pack + - tiered + type: string + token_cost: + type: number + required: + - package_type + - included_ids + - dropped_ids + - evidence_roles + - episode_count + - date_count + - has_current_marker + - has_conflict_block + - token_cost + type: object + retrieval: + properties: + candidate_count: + type: number + candidate_ids: + items: + type: string + type: array + query_text: + type: string + skip_repair: + type: boolean + required: + - candidate_ids + - candidate_count + - query_text + - skip_repair + type: object + type: object + retrieval_mode: + enum: + - flat + - tiered + - abstract-aware + type: string + scope: + anyOf: + - properties: + kind: + enum: + - user + type: string + user_id: + type: string + required: + - kind + - user_id + type: object + - properties: + agent_id: + type: string + agent_scope: {} + kind: + enum: + - workspace + type: string + user_id: + type: string + workspace_id: + type: string + required: + - kind + - user_id + - workspace_id + - agent_id + type: object + description: "Echoed scope: user-scoped or workspace-scoped." + tier_assignments: + items: + properties: + estimated_tokens: + type: number + memory_id: + type: string + tier: + type: string + required: + - memory_id + - tier + - estimated_tokens + type: object + type: array + required: + - count + - retrieval_mode + - scope + - memories type: object description: Search results with injection_text and citations. "400": @@ -1602,8 +2696,233 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Search results with injection_text, citations, and optional traces. + properties: + citations: + items: + type: string + type: array + consensus: + properties: + filtered_count: + type: number + original_count: + type: number + removed_count: + type: number + removed_memory_ids: + items: + type: string + type: array + required: + - original_count + - filtered_count + - removed_count + - removed_memory_ids + type: object + count: + type: number + estimated_context_tokens: + type: number + expand_ids: + items: + type: string + type: array + injection_text: + type: string + lesson_check: + properties: + highest_severity: + type: string + matched_count: + type: number + safe: + type: boolean + warnings: + items: {} + type: array + required: + - safe + - warnings + - highest_severity + - matched_count + type: object + memories: + items: + description: Projected memory record in a search result. + properties: + content: + type: string + created_at: + type: string + id: + type: string + importance: + type: number + score: + type: number + similarity: + type: number + source_site: + type: string + required: + - id + - content + type: object + type: array + observability: + description: Retrieval pipeline trace summaries. + properties: + assembly: + properties: + blocks: + items: + type: string + type: array + final_ids: + items: + type: string + type: array + final_token_cost: + type: number + primary_evidence_position: + type: + - number + - "null" + token_budget: + type: + - number + - "null" + required: + - final_ids + - final_token_cost + - token_budget + - primary_evidence_position + - blocks + type: object + packaging: + properties: + date_count: + type: number + dropped_ids: + items: + type: string + type: array + episode_count: + type: number + evidence_roles: + additionalProperties: + enum: + - primary + - supporting + - historical + - contextual + type: string + type: object + has_conflict_block: + type: boolean + has_current_marker: + type: boolean + included_ids: + items: + type: string + type: array + package_type: + enum: + - subject-pack + - timeline-pack + - tiered + type: string + token_cost: + type: number + required: + - package_type + - included_ids + - dropped_ids + - evidence_roles + - episode_count + - date_count + - has_current_marker + - has_conflict_block + - token_cost + type: object + retrieval: + properties: + candidate_count: + type: number + candidate_ids: + items: + type: string + type: array + query_text: + type: string + skip_repair: + type: boolean + required: + - candidate_ids + - candidate_count + - query_text + - skip_repair + type: object + type: object + retrieval_mode: + enum: + - flat + - tiered + - abstract-aware + type: string + scope: + anyOf: + - properties: + kind: + enum: + - user + type: string + user_id: + type: string + required: + - kind + - user_id + type: object + - properties: + agent_id: + type: string + agent_scope: {} + kind: + enum: + - workspace + type: string + user_id: + type: string + workspace_id: + type: string + required: + - kind + - user_id + - workspace_id + - agent_id + type: object + description: "Echoed scope: user-scoped or workspace-scoped." + tier_assignments: + items: + properties: + estimated_tokens: + type: number + memory_id: + type: string + tier: + type: string + required: + - memory_id + - tier + - estimated_tokens + type: object + type: array + required: + - count + - retrieval_mode + - scope + - memories type: object description: Search results. "400": @@ -1652,8 +2971,20 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Aggregate memory stats for a user. + properties: + avg_importance: + type: number + count: + type: number + source_distribution: + additionalProperties: + type: number + type: object + required: + - count + - avg_importance + - source_distribution type: object description: Stats payload. "400": @@ -1719,8 +3050,14 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Successful no-payload operation. + properties: + success: + enum: + - true + type: boolean + required: + - success type: object description: Deletion success. "400": @@ -1800,7 +3137,111 @@ paths: application/json: schema: additionalProperties: {} - properties: {} + description: Full memory row as emitted by core. + properties: + access_count: + type: number + agent_id: + type: + - string + - "null" + content: + type: string + created_at: + type: string + deleted_at: + type: + - string + - "null" + embedding: + items: + type: number + type: array + episode_id: + type: + - string + - "null" + expired_at: + type: + - string + - "null" + id: + type: string + importance: + type: number + keywords: + type: string + last_accessed_at: + type: string + memory_type: + type: string + metadata: + additionalProperties: {} + type: object + namespace: + type: + - string + - "null" + network: {} + observation_subject: + type: + - string + - "null" + observed_at: + type: string + opinion_confidence: + type: + - number + - "null" + overview: + type: string + source_site: + type: string + source_url: + type: string + status: + enum: + - active + - needs_clarification + type: string + summary: + type: string + trust_score: + type: number + user_id: + type: string + visibility: + enum: + - agent_only + - restricted + - workspace + - null + type: + - string + - "null" + workspace_id: + type: + - string + - "null" + required: + - id + - user_id + - content + - embedding + - memory_type + - importance + - source_site + - source_url + - status + - metadata + - keywords + - summary + - overview + - trust_score + - observed_at + - created_at + - last_accessed_at + - access_count type: object description: Memory object. "400": @@ -1869,8 +3310,82 @@ paths: content: application/json: schema: - additionalProperties: {} - properties: {} + description: Full version trail for a single memory. + properties: + memory_id: + type: string + trail: + items: + description: Single entry in a memory's audit trail. + properties: + actor_model: + type: + - string + - "null" + claim_id: + type: string + content: + type: string + contradiction_confidence: + type: + - number + - "null" + memory_id: + type: + - string + - "null" + mutation_reason: + type: + - string + - "null" + mutation_type: + enum: + - add + - update + - supersede + - delete + - clarify + - null + type: + - string + - "null" + previous_version_id: + type: + - string + - "null" + superseded_by_version_id: + type: + - string + - "null" + valid_from: + type: string + valid_to: + type: + - string + - "null" + version_id: + type: string + required: + - version_id + - claim_id + - content + - mutation_type + - mutation_reason + - actor_model + - contradiction_confidence + - previous_version_id + - superseded_by_version_id + - valid_from + - valid_to + - memory_id + type: object + type: array + version_count: + type: number + required: + - memory_id + - trail + - version_count type: object description: Audit trail. "400": diff --git a/src/schemas/openapi.ts b/src/schemas/openapi.ts index 9e558d8..40f4e3a 100644 --- a/src/schemas/openapi.ts +++ b/src/schemas/openapi.ts @@ -49,6 +49,33 @@ import { ConflictIdParamSchema, ResolveConflictBodySchema, } from './agents'; +import { + IngestResponseSchema, + SearchResponseSchema, + ExpandResponseSchema, + ListResponseSchema, + GetMemoryResponseSchema, + StatsResponseSchema, + HealthResponseSchema, + ConfigUpdateResponseSchema, + ConsolidateResponseSchema, + DecayResponseSchema, + CapResponseSchema, + LessonsListResponseSchema, + LessonStatsResponseSchema, + LessonReportResponseSchema, + ReconciliationResponseSchema, + ReconcileStatusResponseSchema, + ResetSourceResponseSchema, + SuccessResponseSchema, + MutationSummaryResponseSchema, + AuditRecentResponseSchema, + AuditTrailResponseSchema, + TrustResponseSchema, + ConflictsListResponseSchema, + ResolveConflictResponseSchema, + AutoResolveConflictsResponseSchema, +} from './responses'; export const API_TITLE = 'AtomicMemory HTTP API'; export const API_VERSION = '1.0.0'; @@ -117,7 +144,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Ingest a conversation transcript with full extraction.', request: { body: { content: { 'application/json': { schema: IngestBodySchema } }, required: true } }, responses: { - 200: ok('Ingest result with extracted facts.', GenericObjectResponse), + 200: ok('Ingest result with extracted facts.', IngestResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -131,7 +158,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Quick ingest (storeVerbatim when skip_extraction=true).', request: { body: { content: { 'application/json': { schema: IngestBodySchema } }, required: true } }, responses: { - 200: ok('Ingest result.', GenericObjectResponse), + 200: ok('Ingest result.', IngestResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -145,7 +172,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Full semantic search with optional temporal / retrieval-mode / token-budget controls.', request: { body: { content: { 'application/json': { schema: SearchBodySchema } }, required: true } }, responses: { - 200: ok('Search results with injection_text and citations.', GenericObjectResponse), + 200: ok('Search results with injection_text and citations.', SearchResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -159,7 +186,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Latency-optimized search (skips LLM repair loop). ~88% lower latency than /search.', request: { body: { content: { 'application/json': { schema: SearchBodySchema } }, required: true } }, responses: { - 200: ok('Search results.', GenericObjectResponse), + 200: ok('Search results.', SearchResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -173,7 +200,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Expand a list of memory IDs into full objects.', request: { body: { content: { 'application/json': { schema: ExpandBodySchema } }, required: true } }, responses: { - 200: ok('Expanded memories array.', GenericObjectResponse), + 200: ok('Expanded memories array.', ExpandResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -187,7 +214,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'List memories for a user (or workspace).', request: { query: ListQuerySchema }, responses: { - 200: ok('Paginated memory list.', GenericObjectResponse), + 200: ok('Paginated memory list.', ListResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -201,7 +228,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Fetch a single memory by UUID.', request: { params: UuidIdParamSchema, query: MemoryByIdQuerySchema }, responses: { - 200: ok('Memory object.', GenericObjectResponse), + 200: ok('Memory object.', GetMemoryResponseSchema), 400: RESPONSE_400, 404: RESPONSE_404, 500: RESPONSE_500, @@ -216,7 +243,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Delete a single memory by UUID.', request: { params: UuidIdParamSchema, query: MemoryByIdQuerySchema }, responses: { - 200: ok('Deletion success.', GenericObjectResponse), + 200: ok('Deletion success.', SuccessResponseSchema), 400: RESPONSE_400, 404: RESPONSE_404, 500: RESPONSE_500, @@ -231,7 +258,7 @@ function registerMemoryCoreRoutes(registry: OpenAPIRegistry): void { summary: 'Aggregate memory statistics for a user.', request: { query: UserIdQuerySchema }, responses: { - 200: ok('Stats payload.', GenericObjectResponse), + 200: ok('Stats payload.', StatsResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -251,7 +278,7 @@ function registerMemoryLifecycleRoutes(registry: OpenAPIRegistry): void { summary: 'Compute consolidation candidates; optionally execute (execute=true).', request: { body: { content: { 'application/json': { schema: ConsolidateBodySchema } }, required: true } }, responses: { - 200: ok('Consolidation result.', GenericObjectResponse), + 200: ok('Consolidation result.', ConsolidateResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -265,7 +292,7 @@ function registerMemoryLifecycleRoutes(registry: OpenAPIRegistry): void { summary: 'Evaluate decay candidates. dry_run=false archives them.', request: { body: { content: { 'application/json': { schema: DecayBodySchema } }, required: true } }, responses: { - 200: ok('Decay evaluation + archived count.', GenericObjectResponse), + 200: ok('Decay evaluation + archived count.', DecayResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -279,7 +306,7 @@ function registerMemoryLifecycleRoutes(registry: OpenAPIRegistry): void { summary: "Memory-cap status for a user's store.", request: { query: UserIdQuerySchema }, responses: { - 200: ok('Cap status.', GenericObjectResponse), + 200: ok('Cap status.', CapResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -293,7 +320,7 @@ function registerMemoryLifecycleRoutes(registry: OpenAPIRegistry): void { summary: 'Reconcile deferred mutations for a user (or all users when user_id is absent).', request: { body: { content: { 'application/json': { schema: ReconcileBodySchema } }, required: false } }, responses: { - 200: ok('Reconciliation result.', GenericObjectResponse), + 200: ok('Reconciliation result.', ReconciliationResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -307,7 +334,7 @@ function registerMemoryLifecycleRoutes(registry: OpenAPIRegistry): void { summary: 'Get deferred-mutation reconciliation status.', request: { query: UserIdQuerySchema }, responses: { - 200: ok('Status payload.', GenericObjectResponse), + 200: ok('Status payload.', ReconcileStatusResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -321,7 +348,7 @@ function registerMemoryLifecycleRoutes(registry: OpenAPIRegistry): void { summary: 'Delete all memories for a given user + source_site.', request: { body: { content: { 'application/json': { schema: ResetSourceBodySchema } }, required: true } }, responses: { - 200: ok('Reset result.', GenericObjectResponse), + 200: ok('Reset result.', ResetSourceResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -341,7 +368,7 @@ function registerMemoryAuditRoutes(registry: OpenAPIRegistry): void { summary: "Aggregate mutation statistics for a user's memory store.", request: { query: UserIdQuerySchema }, responses: { - 200: ok('Mutation summary.', GenericObjectResponse), + 200: ok('Mutation summary.', MutationSummaryResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -355,7 +382,7 @@ function registerMemoryAuditRoutes(registry: OpenAPIRegistry): void { summary: 'Recent mutations for a user, limit-bounded.', request: { query: UserIdLimitQuerySchema }, responses: { - 200: ok('Recent mutations.', GenericObjectResponse), + 200: ok('Recent mutations.', AuditRecentResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -369,7 +396,7 @@ function registerMemoryAuditRoutes(registry: OpenAPIRegistry): void { summary: 'Per-memory version history.', request: { params: UuidIdParamSchema, query: UserIdQuerySchema }, responses: { - 200: ok('Audit trail.', GenericObjectResponse), + 200: ok('Audit trail.', AuditTrailResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -389,7 +416,7 @@ function registerMemoryLessonRoutes(registry: OpenAPIRegistry): void { summary: 'List active lessons for a user.', request: { query: UserIdQuerySchema }, responses: { - 200: ok('Lessons list.', GenericObjectResponse), + 200: ok('Lessons list.', LessonsListResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -403,7 +430,7 @@ function registerMemoryLessonRoutes(registry: OpenAPIRegistry): void { summary: 'Lesson statistics for a user.', request: { query: UserIdQuerySchema }, responses: { - 200: ok('Stats.', GenericObjectResponse), + 200: ok('Stats.', LessonStatsResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -417,7 +444,7 @@ function registerMemoryLessonRoutes(registry: OpenAPIRegistry): void { summary: 'Report a new lesson.', request: { body: { content: { 'application/json': { schema: LessonReportBodySchema } }, required: true } }, responses: { - 200: ok('Lesson id.', GenericObjectResponse), + 200: ok('Lesson id.', LessonReportResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -431,7 +458,7 @@ function registerMemoryLessonRoutes(registry: OpenAPIRegistry): void { summary: 'Deactivate a lesson by id.', request: { params: FreeIdParamSchema, query: UserIdQuerySchema }, responses: { - 200: ok('Success.', GenericObjectResponse), + 200: ok('Success.', SuccessResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -450,7 +477,7 @@ function registerMemoryConfigRoutes(registry: OpenAPIRegistry): void { tags: [TAG_CONFIG], summary: 'Subsystem liveness + current runtime config snapshot.', responses: { - 200: ok('Status + config snapshot.', GenericObjectResponse), + 200: ok('Status + config snapshot.', HealthResponseSchema), }, }); @@ -464,7 +491,7 @@ function registerMemoryConfigRoutes(registry: OpenAPIRegistry): void { 'Set CORE_RUNTIME_CONFIG_MUTATION_ENABLED=true to enable. Startup-only fields (embedding_provider/model, llm_provider/model) return 400 with a `rejected` array listing the offending fields.', request: { body: { content: { 'application/json': { schema: ConfigBodySchema } }, required: true } }, responses: { - 200: ok('Applied changes + config snapshot.', GenericObjectResponse), + 200: ok('Applied changes + config snapshot.', ConfigUpdateResponseSchema), 400: { // Two shapes are possible: // 1. Basic `{ error }` when the validateBody middleware @@ -505,7 +532,7 @@ function registerAgentRoutes(registry: OpenAPIRegistry): void { summary: "Set the calling user's trust level for a given agent.", request: { body: { content: { 'application/json': { schema: SetTrustBodySchema } }, required: true } }, responses: { - 200: ok('Agent id + applied trust level.', GenericObjectResponse), + 200: ok('Agent id + applied trust level.', TrustResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -519,7 +546,7 @@ function registerAgentRoutes(registry: OpenAPIRegistry): void { summary: 'Look up the trust level for a (user, agent) pair.', request: { query: GetTrustQuerySchema }, responses: { - 200: ok('Agent id + trust level.', GenericObjectResponse), + 200: ok('Agent id + trust level.', TrustResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -533,7 +560,7 @@ function registerAgentRoutes(registry: OpenAPIRegistry): void { summary: 'List open agent conflicts for a user.', request: { query: UserIdFromQuerySchema }, responses: { - 200: ok('Conflicts list.', GenericObjectResponse), + 200: ok('Conflicts list.', ConflictsListResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -550,7 +577,7 @@ function registerAgentRoutes(registry: OpenAPIRegistry): void { body: { content: { 'application/json': { schema: ResolveConflictBodySchema } }, required: true }, }, responses: { - 200: ok('Resolution confirmation.', GenericObjectResponse), + 200: ok('Resolution confirmation.', ResolveConflictResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, @@ -564,7 +591,7 @@ function registerAgentRoutes(registry: OpenAPIRegistry): void { summary: 'Auto-resolve all expired conflicts for a user.', request: { body: { content: { 'application/json': { schema: UserIdFromBodySchema } }, required: true } }, responses: { - 200: ok('Count of resolved conflicts.', GenericObjectResponse), + 200: ok('Count of resolved conflicts.', AutoResolveConflictsResponseSchema), 400: RESPONSE_400, 500: RESPONSE_500, }, diff --git a/src/schemas/responses.ts b/src/schemas/responses.ts new file mode 100644 index 0000000..0566dea --- /dev/null +++ b/src/schemas/responses.ts @@ -0,0 +1,405 @@ +/** + * @file Zod response schemas for every HTTP route. + * + * Mirrors the wire shapes emitted by `src/routes/memory-response-formatters.ts` + * and inline response literals in `src/routes/memories.ts` + `src/routes/agents.ts`. + * Feeds the OpenAPI registry so `npm run check:openapi` catches drift + * between emitted responses and the declared spec. + * + * Field naming follows the wire contract (snake_case). DB-row schemas + * (`MemoryRowSchema`, `LessonRowSchema`, `ClaimVersionRowSchema`, + * `MemoryConflictRowSchema`) declare the full column set that Express + * serializes — `Date` columns become ISO strings on the wire. + */ + +import { z } from './zod-setup'; + +// --------------------------------------------------------------------------- +// Shared sub-schemas +// --------------------------------------------------------------------------- + +const ScopeResponseSchema = z.union([ + z.object({ kind: z.literal('user'), user_id: z.string() }), + z.object({ + kind: z.literal('workspace'), + user_id: z.string(), + workspace_id: z.string(), + agent_id: z.string(), + agent_scope: z.unknown().optional(), + }), +]).openapi({ description: 'Echoed scope: user-scoped or workspace-scoped.' }); + +const MemoryRowSchema = z.object({ + id: z.string(), + user_id: z.string(), + content: z.string(), + embedding: z.array(z.number()), + memory_type: z.string(), + importance: z.number(), + source_site: z.string(), + source_url: z.string(), + episode_id: z.string().nullable().optional(), + status: z.enum(['active', 'needs_clarification']), + metadata: z.record(z.string(), z.unknown()), + keywords: z.string(), + namespace: z.string().nullable().optional(), + summary: z.string(), + overview: z.string(), + trust_score: z.number(), + observed_at: z.string(), + created_at: z.string(), + last_accessed_at: z.string(), + access_count: z.number(), + expired_at: z.string().nullable().optional(), + deleted_at: z.string().nullable().optional(), + network: z.unknown(), + opinion_confidence: z.number().nullable().optional(), + observation_subject: z.string().nullable().optional(), + workspace_id: z.string().nullable().optional(), + agent_id: z.string().nullable().optional(), + visibility: z.enum(['agent_only', 'restricted', 'workspace']).nullable().optional(), +}).passthrough().openapi({ description: 'Full memory row as emitted by core.' }); + +const SearchMemoryItemSchema = z.object({ + id: z.string(), + content: z.string(), + similarity: z.number().optional(), + score: z.number().optional(), + importance: z.number().optional(), + source_site: z.string().optional(), + created_at: z.string().optional(), +}).openapi({ description: 'Projected memory record in a search result.' }); + +const TierAssignmentSchema = z.object({ + memory_id: z.string(), + tier: z.string(), + estimated_tokens: z.number(), +}); + +const LessonCheckSchema = z.object({ + safe: z.boolean(), + warnings: z.array(z.unknown()), + highest_severity: z.string(), + matched_count: z.number(), +}); + +const ConsensusResponseSchema = z.object({ + original_count: z.number(), + filtered_count: z.number(), + removed_count: z.number(), + removed_memory_ids: z.array(z.string()), +}); + +const RetrievalTraceSchema = z.object({ + candidate_ids: z.array(z.string()), + candidate_count: z.number(), + query_text: z.string(), + skip_repair: z.boolean(), +}); + +const PackagingTraceSchema = z.object({ + package_type: z.enum(['subject-pack', 'timeline-pack', 'tiered']), + included_ids: z.array(z.string()), + dropped_ids: z.array(z.string()), + evidence_roles: z.record(z.string(), z.enum(['primary', 'supporting', 'historical', 'contextual'])), + episode_count: z.number(), + date_count: z.number(), + has_current_marker: z.boolean(), + has_conflict_block: z.boolean(), + token_cost: z.number(), +}); + +const AssemblyTraceSchema = z.object({ + final_ids: z.array(z.string()), + final_token_cost: z.number(), + token_budget: z.number().nullable(), + primary_evidence_position: z.number().nullable(), + blocks: z.array(z.string()), +}); + +const ObservabilityResponseSchema = z.object({ + retrieval: RetrievalTraceSchema.optional(), + packaging: PackagingTraceSchema.optional(), + assembly: AssemblyTraceSchema.optional(), +}).openapi({ description: 'Retrieval pipeline trace summaries.' }); + +const ClusterCandidateSchema = z.object({ + member_ids: z.array(z.string()), + member_contents: z.array(z.string()), + avg_affinity: z.number(), + member_count: z.number(), +}); + +const DecayCandidateSchema = z.object({ + id: z.string(), + content: z.string(), + retention_score: z.number(), + importance: z.number(), + days_since_access: z.number(), + access_count: z.number(), +}); + +const LessonRowSchema = z.object({ + id: z.string(), + user_id: z.string(), + lesson_type: z.enum([ + 'injection_blocked', + 'false_memory', + 'contradiction_pattern', + 'user_reported', + 'consensus_violation', + 'trust_violation', + ]), + pattern: z.string(), + embedding: z.array(z.number()), + source_memory_ids: z.array(z.string()), + source_query: z.string().nullable(), + severity: z.enum(['low', 'medium', 'high', 'critical']), + active: z.boolean(), + metadata: z.record(z.string(), z.unknown()), + created_at: z.string(), +}).passthrough().openapi({ description: 'Lesson row from the repository.' }); + +const ClaimVersionRowSchema = z.object({ + id: z.string(), + claim_id: z.string(), + user_id: z.string(), + memory_id: z.string().nullable().optional(), + content: z.string(), + embedding: z.array(z.number()), + importance: z.number(), + source_site: z.string(), + source_url: z.string(), + episode_id: z.string().nullable().optional(), + valid_from: z.string(), + valid_to: z.string().nullable().optional(), + superseded_by_version_id: z.string().nullable().optional(), + mutation_type: z.enum(['add', 'update', 'supersede', 'delete', 'clarify']).nullable().optional(), + mutation_reason: z.string().nullable().optional(), + previous_version_id: z.string().nullable().optional(), + actor_model: z.string().nullable().optional(), + contradiction_confidence: z.number().nullable().optional(), + created_at: z.string(), +}).passthrough().openapi({ description: 'Claim-version row (one snapshot in a memory\'s history).' }); + +const MemoryConflictRowSchema = z.object({ + id: z.string(), + user_id: z.string(), + new_memory_id: z.string().nullable(), + existing_memory_id: z.string().nullable(), + new_agent_id: z.string().nullable(), + existing_agent_id: z.string().nullable(), + new_trust_level: z.number().nullable(), + existing_trust_level: z.number().nullable(), + contradiction_confidence: z.number(), + clarification_note: z.string().nullable(), + status: z.enum(['open', 'resolved_new', 'resolved_existing', 'resolved_both', 'auto_resolved']), + resolution_policy: z.string().nullable(), + resolved_at: z.string().nullable(), + created_at: z.string(), + auto_resolve_after: z.string().nullable(), +}).passthrough().openapi({ description: 'Memory conflict row from the repository.' }); + +const HealthConfigResponseSchema = z.object({ + retrieval_profile: z.string(), + embedding_provider: z.string(), + embedding_model: z.string(), + llm_provider: z.string(), + llm_model: z.string(), + clarification_conflict_threshold: z.number(), + max_search_results: z.number(), + hybrid_search_enabled: z.boolean(), + iterative_retrieval_enabled: z.boolean(), + entity_graph_enabled: z.boolean(), + cross_encoder_enabled: z.boolean(), + agentic_retrieval_enabled: z.boolean(), + repair_loop_enabled: z.boolean(), +}).openapi({ description: 'Runtime config snapshot returned by /health + /config.' }); + +// --------------------------------------------------------------------------- +// Per-route response schemas +// --------------------------------------------------------------------------- + +export const IngestResponseSchema = z.object({ + episode_id: z.string(), + facts_extracted: z.number(), + memories_stored: z.number(), + memories_updated: z.number(), + memories_deleted: z.number(), + memories_skipped: z.number(), + stored_memory_ids: z.array(z.string()), + updated_memory_ids: z.array(z.string()), + links_created: z.number(), + composites_created: z.number(), +}).openapi({ description: 'Ingest result: extraction counts + stored/updated memory IDs.' }); + +export const SearchResponseSchema = z.object({ + count: z.number(), + retrieval_mode: z.enum(['flat', 'tiered', 'abstract-aware']), + scope: ScopeResponseSchema, + memories: z.array(SearchMemoryItemSchema), + injection_text: z.string().optional(), + citations: z.array(z.string()).optional(), + tier_assignments: z.array(TierAssignmentSchema).optional(), + expand_ids: z.array(z.string()).optional(), + estimated_context_tokens: z.number().optional(), + lesson_check: LessonCheckSchema.optional(), + consensus: ConsensusResponseSchema.optional(), + observability: ObservabilityResponseSchema.optional(), +}).openapi({ description: 'Search results with injection_text, citations, and optional traces.' }); + +export const ExpandResponseSchema = z.object({ + memories: z.array(MemoryRowSchema), +}).openapi({ description: 'Expanded memory rows for the requested IDs.' }); + +export const ListResponseSchema = z.object({ + memories: z.array(MemoryRowSchema), + count: z.number(), +}).openapi({ description: 'Paginated memory list.' }); + +export const GetMemoryResponseSchema = MemoryRowSchema; + +export const StatsResponseSchema = z.object({ + count: z.number(), + avg_importance: z.number(), + source_distribution: z.record(z.string(), z.number()), +}).openapi({ description: 'Aggregate memory stats for a user.' }); + +export const HealthResponseSchema = z.object({ + status: z.literal('ok'), + config: HealthConfigResponseSchema, +}).openapi({ description: 'Health + runtime config snapshot.' }); + +export const ConfigUpdateResponseSchema = z.object({ + applied: z.array(z.string()), + config: HealthConfigResponseSchema, + note: z.string(), +}).openapi({ description: 'Applied config updates + full post-update snapshot.' }); + +const ConsolidateScanResponseSchema = z.object({ + memories_scanned: z.number(), + clusters_found: z.number(), + memories_in_clusters: z.number(), + clusters: z.array(ClusterCandidateSchema), +}).openapi({ description: 'Consolidation dry-run (execute=false).' }); + +const ConsolidateExecuteResponseSchema = z.object({ + clusters_consolidated: z.number(), + memories_archived: z.number(), + memories_created: z.number(), + consolidated_memory_ids: z.array(z.string()), +}).openapi({ description: 'Consolidation execution result (execute=true).' }); + +export const ConsolidateResponseSchema = z.union([ + ConsolidateScanResponseSchema, + ConsolidateExecuteResponseSchema, +]).openapi({ description: 'Consolidation result — scan or execute.' }); + +export const DecayResponseSchema = z.object({ + memories_evaluated: z.number(), + candidates_for_archival: z.array(DecayCandidateSchema), + retention_threshold: z.number(), + avg_retention_score: z.number(), + archived: z.number(), +}).openapi({ description: 'Decay evaluation (+ archive count when not dry-run).' }); + +export const CapResponseSchema = z.object({ + active_memories: z.number(), + max_memories: z.number(), + status: z.enum(['ok', 'warn', 'exceeded']), + usage_ratio: z.number(), + recommendation: z.enum(['none', 'consolidate', 'decay', 'consolidate-and-decay']), +}).openapi({ description: 'Memory cap status and recommendation.' }); + +export const LessonsListResponseSchema = z.object({ + lessons: z.array(LessonRowSchema), + count: z.number(), +}).openapi({ description: 'Active lessons for a user.' }); + +export const LessonStatsResponseSchema = z.object({ + total_active: z.number(), + by_type: z.record(z.string(), z.number()), +}).openapi({ description: 'Aggregate lesson counts by type.' }); + +export const LessonReportResponseSchema = z.object({ + lesson_id: z.string(), +}).openapi({ description: 'ID of the newly-reported lesson.' }); + +export const ReconciliationResponseSchema = z.object({ + processed: z.number(), + resolved: z.number(), + noops: z.number(), + updates: z.number(), + supersedes: z.number(), + deletes: z.number(), + adds: z.number(), + errors: z.number(), + duration_ms: z.number(), +}).openapi({ description: 'Deferred-AUDN reconciliation counters.' }); + +export const ReconcileStatusResponseSchema = z.object({ + pending: z.number(), + enabled: z.boolean(), +}).passthrough().openapi({ description: 'Current deferred-AUDN queue state.' }); + +export const ResetSourceResponseSchema = z.object({ + success: z.literal(true), + deleted_memories: z.number(), + deleted_episodes: z.number(), +}).openapi({ description: 'Reset-by-source deletion counts.' }); + +export const SuccessResponseSchema = z.object({ success: z.literal(true) }) + .openapi({ description: 'Successful no-payload operation.' }); + +export const MutationSummaryResponseSchema = z.object({ + total_versions: z.number(), + active_versions: z.number(), + superseded_versions: z.number(), + total_claims: z.number(), + by_mutation_type: z.record(z.string(), z.number()), +}).openapi({ description: 'Aggregate mutation statistics for a user.' }); + +export const AuditRecentResponseSchema = z.object({ + mutations: z.array(ClaimVersionRowSchema), + count: z.number(), +}).openapi({ description: 'Newest-first mutation rows for a user.' }); + +const AuditTrailEntryResponseSchema = z.object({ + version_id: z.string(), + claim_id: z.string(), + content: z.string(), + mutation_type: z.enum(['add', 'update', 'supersede', 'delete', 'clarify']).nullable(), + mutation_reason: z.string().nullable(), + actor_model: z.string().nullable(), + contradiction_confidence: z.number().nullable(), + previous_version_id: z.string().nullable(), + superseded_by_version_id: z.string().nullable(), + valid_from: z.string(), + valid_to: z.string().nullable(), + memory_id: z.string().nullable(), +}).openapi({ description: 'Single entry in a memory\'s audit trail.' }); + +export const AuditTrailResponseSchema = z.object({ + memory_id: z.string(), + trail: z.array(AuditTrailEntryResponseSchema), + version_count: z.number(), +}).openapi({ description: 'Full version trail for a single memory.' }); + +export const TrustResponseSchema = z.object({ + agent_id: z.string(), + trust_level: z.number(), +}).openapi({ description: '(userId, agentId) trust record.' }); + +export const ConflictsListResponseSchema = z.object({ + conflicts: z.array(MemoryConflictRowSchema), + count: z.number(), +}).openapi({ description: 'Open agent-trust conflicts for a user.' }); + +export const ResolveConflictResponseSchema = z.object({ + id: z.string(), + status: z.enum(['resolved_new', 'resolved_existing', 'resolved_both']), +}).openapi({ description: 'Resolved-conflict echo.' }); + +export const AutoResolveConflictsResponseSchema = z.object({ + resolved: z.number(), +}).openapi({ description: 'Count of conflicts auto-resolved in the batch pass.' });