From 936f1d64dedc3207e8929fce349bd67532f4e6ff Mon Sep 17 00:00:00 2001 From: OG T Date: Tue, 31 Mar 2026 19:10:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(types):=20Phase=2014.3=20=E5=85=B1?= =?UTF-8?q?=E7=94=A8=E5=9E=8B=E5=88=A5=E7=B3=BB=E7=B5=B1=20(#97-#100)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 建立 Pydantic → TypeScript 自動生成工具鏈: 1. scripts/generate-schemas.py - 從 Pydantic 模型生成 JSON Schema - 正確處理 Pydantic 2.x 的 $defs 格式 - 支援 Approval/Incident/Terminal/Playbook/CSRF 模型 2. packages/shared-types/ - @awoooi/shared-types 套件 - 44 個型別定義,40 個介面 - json-schema-to-typescript 自動生成 3. 前端整合 - apps/web 加入 @awoooi/shared-types 依賴 - typecheck 通過 使用方式: cd packages/shared-types pnpm generate # 重新生成型別 Co-Authored-By: Claude Opus 4.5 --- apps/web/package.json | 1 + packages/shared-types/package.json | 24 + packages/shared-types/schemas/api-types.json | 2212 ++++++++++++++++++ packages/shared-types/src/api-types.ts | 1352 +++++++++++ packages/shared-types/src/index.ts | 16 + packages/shared-types/tsconfig.json | 14 + pnpm-lock.yaml | 49 + scripts/generate-schemas.py | 257 ++ 8 files changed, 3925 insertions(+) create mode 100644 packages/shared-types/package.json create mode 100644 packages/shared-types/schemas/api-types.json create mode 100644 packages/shared-types/src/api-types.ts create mode 100644 packages/shared-types/src/index.ts create mode 100644 packages/shared-types/tsconfig.json create mode 100644 scripts/generate-schemas.py diff --git a/apps/web/package.json b/apps/web/package.json index 12aae9d0..09c08874 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@awoooi/lewooogo-core": "workspace:*", + "@awoooi/shared-types": "workspace:^", "@sentry/nextjs": "^10.45.0", "@tanstack/react-query": "^5.17.0", "class-variance-authority": "^0.7.1", diff --git a/packages/shared-types/package.json b/packages/shared-types/package.json new file mode 100644 index 00000000..611e6333 --- /dev/null +++ b/packages/shared-types/package.json @@ -0,0 +1,24 @@ +{ + "name": "@awoooi/shared-types", + "version": "1.0.0", + "description": "AWOOOI 前後端共用型別定義 (自動生成自 Pydantic)", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "generate:schema": "cd ../../apps/api && python ../../scripts/generate-schemas.py", + "generate:types": "json2ts -i ./schemas/api-types.json -o ./src/api-types.ts --bannerComment \"/* Auto-generated from Pydantic models - DO NOT EDIT */\" --unreachableDefinitions", + "generate": "pnpm generate:schema && pnpm generate:types", + "clean": "rm -rf ./schemas/*.json ./src/api-types.ts" + }, + "devDependencies": { + "json-schema-to-typescript": "^15.0.0", + "typescript": "^5.0.0" + }, + "files": [ + "src", + "schemas" + ], + "publishConfig": { + "access": "public" + } +} diff --git a/packages/shared-types/schemas/api-types.json b/packages/shared-types/schemas/api-types.json new file mode 100644 index 00000000..2e2a4c96 --- /dev/null +++ b/packages/shared-types/schemas/api-types.json @@ -0,0 +1,2212 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AWOOOI API Types", + "description": "Auto-generated from Pydantic models - DO NOT EDIT", + "definitions": { + "ApprovalStatus": { + "description": "授權請求狀態機\n\nPENDING → APPROVED → EXECUTION_SUCCESS\n → EXECUTION_FAILED\nPENDING → REJECTED\nPENDING → EXPIRED", + "enum": [ + "pending", + "approved", + "rejected", + "expired", + "execution_success", + "execution_failed" + ], + "title": "ApprovalStatus", + "type": "string" + }, + "BlastRadius": { + "description": "爆炸半徑 - 影響範圍評估", + "properties": { + "affected_pods": { + "default": 0, + "minimum": 0, + "title": "Affected Pods", + "type": "integer" + }, + "estimated_downtime": { + "default": "0", + "title": "Estimated Downtime", + "type": "string" + }, + "related_services": { + "items": { + "type": "string" + }, + "title": "Related Services", + "type": "array" + }, + "data_impact": { + "$ref": "#/definitions/DataImpact", + "default": "none" + } + }, + "title": "BlastRadius", + "type": "object" + }, + "DataImpact": { + "description": "資料影響類型", + "enum": [ + "none", + "read_only", + "write", + "destructive" + ], + "title": "DataImpact", + "type": "string" + }, + "DryRunCheck": { + "description": "Dry-Run 預演檢查結果", + "properties": { + "name": { + "title": "Name", + "type": "string" + }, + "passed": { + "title": "Passed", + "type": "boolean" + }, + "message": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Message" + } + }, + "required": [ + "name", + "passed" + ], + "title": "DryRunCheck", + "type": "object" + }, + "RiskLevel": { + "description": "風險等級 - 決定所需簽核人數\n\n- LOW: 0 人,自動放行\n- MEDIUM: 需 1 人簽核\n- HIGH: 需 1 人簽核 (信任引擎可降級至 MEDIUM)\n- CRITICAL: 需 2 人 Multi-Sig 雙重簽核 (永不降級)\n\n變更紀錄:\n- 2026-03-25: 新增 HIGH (Phase 16 R2 合併自 trust_engine.py)", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "title": "RiskLevel", + "type": "string" + }, + "Signature": { + "description": "簽核記錄\n\nPhase 5.4.5: 新增 Telegram 審計欄位\n- source: 簽核來源通道\n- telegram_user_id: Telegram User ID (永久追溯憑證)\n- telegram_message_id: Telegram 訊息 ID", + "properties": { + "id": { + "format": "uuid", + "title": "Id", + "type": "string" + }, + "signer_id": { + "description": "簽核者 ID", + "title": "Signer Id", + "type": "string" + }, + "signer_name": { + "description": "簽核者名稱", + "title": "Signer Name", + "type": "string" + }, + "signed_at": { + "format": "date-time", + "title": "Signed At", + "type": "string" + }, + "comment": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Comment" + }, + "source": { + "$ref": "#/definitions/SignatureSource", + "default": "web", + "description": "簽核來源通道 (web/telegram/api/system)" + }, + "telegram_user_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Telegram User ID (永久追溯憑證)", + "title": "Telegram User Id" + }, + "telegram_message_id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Telegram 訊息 ID", + "title": "Telegram Message Id" + } + }, + "required": [ + "signer_id", + "signer_name" + ], + "title": "Signature", + "type": "object" + }, + "SignatureSource": { + "description": "簽核來源通道 (Phase 5.4.5: AuditLog 擴充)\n\n用於追溯簽核是從哪個通道發起", + "enum": [ + "web", + "telegram", + "api", + "system" + ], + "title": "SignatureSource", + "type": "string" + }, + "ApprovalRequest": { + "description": "完整授權請求模型", + "properties": { + "action": { + "description": "執行動作描述", + "title": "Action", + "type": "string" + }, + "description": { + "description": "詳細說明", + "title": "Description", + "type": "string" + }, + "risk_level": { + "$ref": "#/definitions/RiskLevel", + "description": "風險等級" + }, + "blast_radius": { + "$ref": "#/definitions/BlastRadius" + }, + "dry_run_checks": { + "items": { + "$ref": "#/definitions/DryRunCheck" + }, + "title": "Dry Run Checks", + "type": "array" + }, + "requested_by": { + "description": "請求發起者", + "title": "Requested By", + "type": "string" + }, + "expires_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "到期時間", + "title": "Expires At" + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "額外元資料", + "title": "Metadata" + }, + "id": { + "format": "uuid", + "title": "Id", + "type": "string" + }, + "status": { + "$ref": "#/definitions/ApprovalStatus", + "default": "pending" + }, + "required_signatures": { + "description": "所需簽核數", + "title": "Required Signatures", + "type": "integer" + }, + "signatures": { + "items": { + "$ref": "#/definitions/Signature" + }, + "title": "Signatures", + "type": "array" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "title": "Updated At", + "type": "string" + }, + "resolved_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "解決時間", + "title": "Resolved At" + }, + "rejection_reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Rejection Reason" + }, + "fingerprint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "告警指紋 Hash", + "title": "Fingerprint" + }, + "hit_count": { + "default": 1, + "description": "聚合觸發次數", + "title": "Hit Count", + "type": "integer" + }, + "last_seen_at": { + "description": "最後觸發時間", + "format": "date-time", + "title": "Last Seen At", + "type": "string" + } + }, + "required": [ + "action", + "description", + "risk_level", + "requested_by", + "required_signatures" + ], + "title": "ApprovalRequest", + "type": "object" + }, + "ApprovalRequestCreate": { + "description": "建立授權請求 (API 輸入)", + "properties": { + "action": { + "description": "執行動作描述", + "title": "Action", + "type": "string" + }, + "description": { + "description": "詳細說明", + "title": "Description", + "type": "string" + }, + "risk_level": { + "$ref": "#/definitions/RiskLevel", + "description": "風險等級" + }, + "blast_radius": { + "$ref": "#/definitions/BlastRadius" + }, + "dry_run_checks": { + "items": { + "$ref": "#/definitions/DryRunCheck" + }, + "title": "Dry Run Checks", + "type": "array" + }, + "requested_by": { + "description": "請求發起者", + "title": "Requested By", + "type": "string" + }, + "expires_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "到期時間", + "title": "Expires At" + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "額外元資料", + "title": "Metadata" + } + }, + "required": [ + "action", + "description", + "risk_level", + "requested_by" + ], + "title": "ApprovalRequestCreate", + "type": "object" + }, + "ApprovalRequestResponse": { + "description": "授權請求 API 回應", + "properties": { + "id": { + "title": "Id", + "type": "string" + }, + "action": { + "title": "Action", + "type": "string" + }, + "description": { + "title": "Description", + "type": "string" + }, + "status": { + "$ref": "#/definitions/ApprovalStatus" + }, + "risk_level": { + "$ref": "#/definitions/RiskLevel" + }, + "blast_radius": { + "$ref": "#/definitions/BlastRadius" + }, + "dry_run_checks": { + "items": { + "$ref": "#/definitions/DryRunCheck" + }, + "title": "Dry Run Checks", + "type": "array" + }, + "required_signatures": { + "title": "Required Signatures", + "type": "integer" + }, + "current_signatures": { + "title": "Current Signatures", + "type": "integer" + }, + "signatures": { + "items": { + "$ref": "#/definitions/Signature" + }, + "title": "Signatures", + "type": "array" + }, + "requested_by": { + "title": "Requested By", + "type": "string" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "expires_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Expires At" + }, + "resolved_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Resolved At" + }, + "fingerprint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Fingerprint" + }, + "hit_count": { + "default": 1, + "title": "Hit Count", + "type": "integer" + }, + "last_seen_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Last Seen At" + }, + "metadata": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Metadata" + } + }, + "required": [ + "id", + "action", + "description", + "status", + "risk_level", + "blast_radius", + "dry_run_checks", + "required_signatures", + "current_signatures", + "signatures", + "requested_by", + "created_at", + "expires_at", + "resolved_at" + ], + "title": "ApprovalRequestResponse", + "type": "object" + }, + "PendingApprovalsResponse": { + "description": "待簽核清單回應", + "properties": { + "count": { + "title": "Count", + "type": "integer" + }, + "approvals": { + "items": { + "$ref": "#/definitions/ApprovalRequestResponse" + }, + "title": "Approvals", + "type": "array" + } + }, + "required": [ + "count", + "approvals" + ], + "title": "PendingApprovalsResponse", + "type": "object" + }, + "RejectRequest": { + "description": "退回請求", + "properties": { + "rejector_id": { + "description": "退回者 ID", + "title": "Rejector Id", + "type": "string" + }, + "rejector_name": { + "description": "退回者名稱", + "title": "Rejector Name", + "type": "string" + }, + "reason": { + "description": "退回原因", + "title": "Reason", + "type": "string" + } + }, + "required": [ + "rejector_id", + "rejector_name", + "reason" + ], + "title": "RejectRequest", + "type": "object" + }, + "SignRequest": { + "description": "簽核請求", + "properties": { + "signer_id": { + "description": "簽核者 ID", + "title": "Signer Id", + "type": "string" + }, + "signer_name": { + "description": "簽核者名稱", + "title": "Signer Name", + "type": "string" + }, + "comment": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "簽核備註", + "title": "Comment" + } + }, + "required": [ + "signer_id", + "signer_name" + ], + "title": "SignRequest", + "type": "object" + }, + "SignResponse": { + "description": "簽核回應", + "properties": { + "success": { + "title": "Success", + "type": "boolean" + }, + "message": { + "title": "Message", + "type": "string" + }, + "approval": { + "$ref": "#/definitions/ApprovalRequestResponse" + }, + "execution_triggered": { + "default": false, + "description": "是否觸發執行 (當簽核數滿足時)", + "title": "Execution Triggered", + "type": "boolean" + } + }, + "required": [ + "success", + "message", + "approval" + ], + "title": "SignResponse", + "type": "object" + }, + "AIDecisionChain": { + "description": "AI 決策鏈 - 完整記錄推論過程,供稽核使用\n\nCISO 要求:\n- 必須記錄 AI 使用的模型、Prompt 版本\n- 必須記錄推理步驟 (可解釋性)\n- 必須記錄推論延遲 (效能監控)\n\n用於回答:\n- 「AI 為什麼做出這個建議?」\n- 「AI 當時參考了哪些資料?」\n- 「這個決策可以被重現嗎?」", + "properties": { + "input_signal_ids": { + "description": "觸發此推論的告警 ID 列表", + "items": { + "type": "string" + }, + "title": "Input Signal Ids", + "type": "array" + }, + "context_retrieved": { + "description": "從記憶中檢索的上下文摘要", + "items": { + "type": "string" + }, + "title": "Context Retrieved", + "type": "array" + }, + "model_used": { + "description": "使用的 AI 模型 (如 ollama/llama3.2:latest, gemini/gemini-pro)", + "title": "Model Used", + "type": "string" + }, + "prompt_template_version": { + "default": "v1.0.0", + "description": "Prompt 模板版本號", + "title": "Prompt Template Version", + "type": "string" + }, + "hypothesis": { + "description": "AI 的根因推論", + "title": "Hypothesis", + "type": "string" + }, + "confidence": { + "description": "信心指數 (0.0 - 1.0)", + "maximum": 1.0, + "minimum": 0.0, + "title": "Confidence", + "type": "number" + }, + "reasoning_steps": { + "description": "推理步驟 (可解釋性)", + "items": { + "type": "string" + }, + "title": "Reasoning Steps", + "type": "array" + }, + "blast_radius": { + "anyOf": [ + { + "$ref": "#/definitions/BlastRadius" + }, + { + "type": "null" + } + ], + "default": null, + "description": "爆炸半徑分析結果 (復用現有模型)" + }, + "probable_root_causes": { + "description": "可能的根本原因列表", + "items": { + "type": "string" + }, + "title": "Probable Root Causes", + "type": "array" + }, + "inference_started_at": { + "description": "推論開始時間", + "format": "date-time", + "title": "Inference Started At", + "type": "string" + }, + "inference_completed_at": { + "description": "推論完成時間", + "format": "date-time", + "title": "Inference Completed At", + "type": "string" + }, + "latency_ms": { + "description": "推論延遲 (毫秒)", + "title": "Latency Ms", + "type": "integer" + } + }, + "required": [ + "model_used", + "hypothesis", + "confidence", + "inference_started_at", + "inference_completed_at", + "latency_ms" + ], + "title": "AIDecisionChain", + "type": "object" + }, + "IncidentFrequencyStats": { + "description": "事件頻率統計 - ADR-037 監控增強架構\n\n2026-03-29 ogt: 統帥指示「重啟只是治標,太常發生的異常必須徹底解決」\n\n用途:\n- 統計同一異常在不同時間窗口內的發生次數\n- 根據頻率決定修復策略的升級 (Tier 1→4)\n- 讓使用者知道這個問題有多頻繁\n\n升級閾值:\n- REPEAT: ≥ 3 次/24h (標記重複)\n- ESCALATE: ≥ 5 次/24h (升級 Tier,通知 Owner)\n- PERMANENT_FIX: ≥ 10 次/24h (強制根因修復)", + "properties": { + "anomaly_key": { + "description": "異常簽名 Hash (前 16 字元)", + "title": "Anomaly Key", + "type": "string" + }, + "count_1h": { + "default": 0, + "description": "1 小時內發生次數", + "minimum": 0, + "title": "Count 1H", + "type": "integer" + }, + "count_24h": { + "default": 0, + "description": "24 小時內發生次數", + "minimum": 0, + "title": "Count 24H", + "type": "integer" + }, + "count_7d": { + "default": 0, + "description": "7 天內發生次數", + "minimum": 0, + "title": "Count 7D", + "type": "integer" + }, + "count_30d": { + "default": 0, + "description": "30 天內發生次數", + "minimum": 0, + "title": "Count 30D", + "type": "integer" + }, + "escalation_level": { + "anyOf": [ + { + "enum": [ + "REPEAT", + "ESCALATE", + "PERMANENT_FIX" + ], + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "升級建議 (基於 24h 頻率)", + "title": "Escalation Level" + }, + "auto_repair_count": { + "default": 0, + "description": "自動修復嘗試次數", + "minimum": 0, + "title": "Auto Repair Count", + "type": "integer" + }, + "last_repair_action": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "最後一次修復動作", + "title": "Last Repair Action" + }, + "last_repair_success": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "最後一次修復是否成功", + "title": "Last Repair Success" + } + }, + "required": [ + "anomaly_key" + ], + "title": "IncidentFrequencyStats", + "type": "object" + }, + "IncidentOutcome": { + "description": "事件結果 - AI 學習的關鍵回饋\n\nCPO 要求:\n- 必須記錄執行結果 (成功/失敗)\n- 必須收集人類回饋 (AI 建議是否有效)\n- 必須標記是否納入長期記憶\n\n這是讓 AI 「從經驗中學習」的關鍵:\n- 如果 AI 的建議有效 → 強化這個模式\n- 如果 AI 的建議無效 → 記錄為負面案例", + "properties": { + "proposal_executed": { + "default": false, + "description": "是否已執行修復提案", + "title": "Proposal Executed", + "type": "boolean" + }, + "execution_success": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "執行是否成功 (None = 未執行)", + "title": "Execution Success" + }, + "actual_downtime_minutes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "實際停機時間 (分鐘)", + "title": "Actual Downtime Minutes" + }, + "human_feedback": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "人類的文字回饋 (如 '這個建議很準' 或 '下次應該先檢查 X')", + "title": "Human Feedback" + }, + "effectiveness_score": { + "anyOf": [ + { + "maximum": 5, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "有效性評分 (1-5 分)", + "title": "Effectiveness Score" + }, + "should_remember": { + "default": true, + "description": "是否納入長期記憶 (Episodic Memory)", + "title": "Should Remember", + "type": "boolean" + }, + "learning_notes": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "給未來 AI 的學習筆記", + "title": "Learning Notes" + } + }, + "title": "IncidentOutcome", + "type": "object" + }, + "IncidentStatus": { + "description": "事件狀態機\n\nINVESTIGATING → MITIGATING → RESOLVED → CLOSED\n ↘ (無法解決) → ESCALATED", + "enum": [ + "investigating", + "mitigating", + "resolved", + "closed", + "escalated" + ], + "title": "IncidentStatus", + "type": "string" + }, + "Severity": { + "description": "事件嚴重度 (Incident Severity)\n\n與 RiskLevel 的區別:\n- Severity: 事件本身的嚴重程度 (P0 最嚴重)\n- RiskLevel: 修復操作的風險等級 (CRITICAL 最危險)\n\n用於:\n- AI 分層調用策略 (P0 直接用 Claude,P2/P3 用 Ollama)\n- SLA 響應時間門檻\n- 告警通知優先級", + "enum": [ + "P0", + "P1", + "P2", + "P3" + ], + "title": "Severity", + "type": "string" + }, + "Signal": { + "description": "原始告警信號 - 從 Prometheus/SignOz/Alertmanager 接收\n\n這是 Incident 的「感知輸入」,一個 Incident 可能包含多個 Signal。\n例如: CPU Spike + Memory OOM + Pod Restart 三個告警可能屬於同一個 Incident。", + "properties": { + "signal_id": { + "description": "信號唯一識別碼 (8 字元)", + "title": "Signal Id", + "type": "string" + }, + "alert_name": { + "description": "告警名稱 (如 HighCPUUsage)", + "title": "Alert Name", + "type": "string" + }, + "severity": { + "$ref": "#/definitions/Severity", + "description": "告警嚴重度" + }, + "source": { + "description": "告警來源", + "enum": [ + "prometheus", + "signoz", + "alertmanager", + "manual", + "telegram" + ], + "title": "Source", + "type": "string" + }, + "fired_at": { + "description": "告警觸發時間", + "format": "date-time", + "title": "Fired At", + "type": "string" + }, + "resolved_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "告警解除時間", + "title": "Resolved At" + }, + "labels": { + "additionalProperties": { + "type": "string" + }, + "description": "Prometheus 標籤 (如 pod, namespace, service)", + "title": "Labels", + "type": "object" + }, + "annotations": { + "additionalProperties": { + "type": "string" + }, + "description": "告警附加資訊 (如 summary, description)", + "title": "Annotations", + "type": "object" + }, + "fingerprint": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "告警指紋 Hash,用於去重與聚合", + "title": "Fingerprint" + } + }, + "required": [ + "alert_name", + "severity", + "source", + "fired_at" + ], + "title": "Signal", + "type": "object" + }, + "Incident": { + "description": "事件模型 - AWOOOI 認知系統的核心資料結構\n\n這是 AWOOOI 2.0「認知覺醒計畫」的基石,承載了:\n- 感知 (Signals): 原始告警\n- 認知 (Decision Chain): AI 推論過程\n- 決策 (Proposals): 修復建議\n- 記憶 (Outcome): 結果回饋\n\n三層記憶架構:\n┌─────────────────┐\n│ Working Memory │ ← Redis Hash, 7 天 TTL\n│ (活躍事件) │\n└────────┬────────┘\n │ 定期遷移\n ▼\n┌─────────────────┐\n│ Episodic Memory │ ← PostgreSQL, 永久保留\n│ (歷史事件) │\n└────────┬────────┘\n │ 向量化\n ▼\n┌─────────────────┐\n│ Semantic Memory │ ← Vector DB, RAG 檢索\n│ (知識庫) │\n└─────────────────┘", + "properties": { + "incident_id": { + "description": "事件唯一識別碼 (如 INC-20260322-A1B2C3)", + "title": "Incident Id", + "type": "string" + }, + "status": { + "$ref": "#/definitions/IncidentStatus", + "default": "investigating", + "description": "事件狀態" + }, + "severity": { + "$ref": "#/definitions/Severity", + "description": "事件嚴重度" + }, + "signals": { + "description": "關聯的告警信號列表", + "items": { + "$ref": "#/definitions/Signal" + }, + "title": "Signals", + "type": "array" + }, + "affected_services": { + "description": "受影響的服務列表 (GraphRAG Blast Radius)", + "items": { + "type": "string" + }, + "title": "Affected Services", + "type": "array" + }, + "decision_chain": { + "anyOf": [ + { + "$ref": "#/definitions/AIDecisionChain" + }, + { + "type": "null" + } + ], + "default": null, + "description": "AI 決策鏈 (完整推論過程)" + }, + "proposal_ids": { + "description": "關聯的 ApprovalRequest ID 列表 (支援多重決策軌跡)", + "items": { + "format": "uuid", + "type": "string" + }, + "title": "Proposal Ids", + "type": "array" + }, + "outcome": { + "anyOf": [ + { + "$ref": "#/definitions/IncidentOutcome" + }, + { + "type": "null" + } + ], + "default": null, + "description": "事件結果與人類回饋" + }, + "frequency_stats": { + "anyOf": [ + { + "$ref": "#/definitions/IncidentFrequencyStats" + }, + { + "type": "null" + } + ], + "default": null, + "description": "異常頻率統計 (用於 Tier 分級修復策略)" + }, + "created_at": { + "description": "事件建立時間", + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "updated_at": { + "description": "最後更新時間", + "format": "date-time", + "title": "Updated At", + "type": "string" + }, + "resolved_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "事件解決時間", + "title": "Resolved At" + }, + "closed_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "事件關閉時間 (含回饋)", + "title": "Closed At" + }, + "ttl_days": { + "default": 7, + "description": "Working Memory TTL (天)", + "title": "Ttl Days", + "type": "integer" + }, + "persisted_to_pg": { + "default": false, + "description": "是否已固化到 PostgreSQL (Episodic Memory)", + "title": "Persisted To Pg", + "type": "boolean" + }, + "vectorized": { + "default": false, + "description": "是否已向量化到 Vector DB (Semantic Memory)", + "title": "Vectorized", + "type": "boolean" + } + }, + "required": [ + "severity" + ], + "title": "Incident", + "type": "object" + }, + "IncidentCreate": { + "description": "建立事件的 DTO", + "properties": { + "severity": { + "$ref": "#/definitions/Severity" + }, + "signals": { + "items": { + "$ref": "#/definitions/Signal" + }, + "title": "Signals", + "type": "array" + }, + "affected_services": { + "items": { + "type": "string" + }, + "title": "Affected Services", + "type": "array" + } + }, + "required": [ + "severity" + ], + "title": "IncidentCreate", + "type": "object" + }, + "IncidentResponse": { + "description": "事件 API 回應", + "properties": { + "incident_id": { + "title": "Incident Id", + "type": "string" + }, + "status": { + "$ref": "#/definitions/IncidentStatus" + }, + "severity": { + "$ref": "#/definitions/Severity" + }, + "signals": { + "items": { + "$ref": "#/definitions/Signal" + }, + "title": "Signals", + "type": "array" + }, + "affected_services": { + "items": { + "type": "string" + }, + "title": "Affected Services", + "type": "array" + }, + "decision_chain": { + "anyOf": [ + { + "$ref": "#/definitions/AIDecisionChain" + }, + { + "type": "null" + } + ] + }, + "proposal_ids": { + "items": { + "type": "string" + }, + "title": "Proposal Ids", + "type": "array" + }, + "outcome": { + "anyOf": [ + { + "$ref": "#/definitions/IncidentOutcome" + }, + { + "type": "null" + } + ] + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "title": "Updated At", + "type": "string" + }, + "resolved_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Resolved At" + }, + "closed_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Closed At" + } + }, + "required": [ + "incident_id", + "status", + "severity", + "signals", + "affected_services", + "decision_chain", + "proposal_ids", + "outcome", + "created_at", + "updated_at", + "resolved_at", + "closed_at" + ], + "title": "IncidentResponse", + "type": "object" + }, + "IncidentUpdate": { + "description": "更新事件的 DTO", + "properties": { + "status": { + "anyOf": [ + { + "$ref": "#/definitions/IncidentStatus" + }, + { + "type": "null" + } + ], + "default": null + }, + "severity": { + "anyOf": [ + { + "$ref": "#/definitions/Severity" + }, + { + "type": "null" + } + ], + "default": null + }, + "affected_services": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Affected Services" + }, + "decision_chain": { + "anyOf": [ + { + "$ref": "#/definitions/AIDecisionChain" + }, + { + "type": "null" + } + ], + "default": null + }, + "outcome": { + "anyOf": [ + { + "$ref": "#/definitions/IncidentOutcome" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "IncidentUpdate", + "type": "object" + }, + "SpatialContext": { + "description": "空間感知上下文 (Ghost Payload)\n\n前端隱形夾帶,讓 AI 知道使用者正在看什麼", + "properties": { + "current_page": { + "description": "統帥當前所在的路由", + "examples": [ + "/zh-TW/authorizations", + "/zh-TW" + ], + "title": "Current Page", + "type": "string" + }, + "focused_entity_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "正在檢視的實體 ID (incident/approval)", + "examples": [ + "INC-2026-0001", + "APR-2026-0001" + ], + "title": "Focused Entity Id" + } + }, + "required": [ + "current_page" + ], + "title": "SpatialContext", + "type": "object" + }, + "TerminalIntentRequest": { + "description": "Terminal Intent 請求\n\n統帥輸入的指令或問題", + "properties": { + "intent": { + "description": "統帥輸入的原始指令或意圖", + "examples": [ + "列出所有待審核的 approval", + "為什麼 awoooi-api pod 一直重啟?" + ], + "maxLength": 2000, + "minLength": 1, + "title": "Intent", + "type": "string" + }, + "context": { + "$ref": "#/definitions/SpatialContext", + "description": "前端空間感知上下文" + }, + "session_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "現有 Session ID (用於續傳)", + "title": "Session Id" + } + }, + "required": [ + "intent", + "context" + ], + "title": "TerminalIntentRequest", + "type": "object" + }, + "TerminalIntentResponse": { + "description": "Intent 請求回應\n\n返回 session_id 供前端訂閱 SSE", + "properties": { + "session_id": { + "description": "Session UUID", + "title": "Session Id", + "type": "string" + }, + "stream_url": { + "description": "SSE 串流訂閱 URL", + "title": "Stream Url", + "type": "string" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + } + }, + "required": [ + "session_id", + "stream_url" + ], + "title": "TerminalIntentResponse", + "type": "object" + }, + "TerminalSessionStatus": { + "description": "Terminal Session 狀態", + "enum": [ + "pending", + "processing", + "completed", + "aborted", + "error" + ], + "title": "TerminalSessionStatus", + "type": "string" + }, + "TerminalStatusResponse": { + "description": "Session 狀態查詢回應", + "properties": { + "session_id": { + "title": "Session Id", + "type": "string" + }, + "status": { + "$ref": "#/definitions/TerminalSessionStatus" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "last_event_id": { + "title": "Last Event Id", + "type": "integer" + }, + "message_count": { + "title": "Message Count", + "type": "integer" + } + }, + "required": [ + "session_id", + "status", + "created_at", + "last_event_id", + "message_count" + ], + "title": "TerminalStatusResponse", + "type": "object" + }, + "TerminalAbortRequest": { + "description": "中斷執行請求", + "properties": { + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "中斷原因", + "title": "Reason" + } + }, + "title": "TerminalAbortRequest", + "type": "object" + }, + "TerminalAbortResponse": { + "description": "中斷執行回應", + "properties": { + "session_id": { + "title": "Session Id", + "type": "string" + }, + "aborted": { + "title": "Aborted", + "type": "boolean" + }, + "message": { + "title": "Message", + "type": "string" + } + }, + "required": [ + "session_id", + "aborted", + "message" + ], + "title": "TerminalAbortResponse", + "type": "object" + }, + "TerminalThoughtEvent": { + "description": "AI 思考軌跡事件", + "properties": { + "agent": { + "description": "代理人名稱", + "examples": [ + "System", + "Investigator", + "Strategist" + ], + "title": "Agent", + "type": "string" + }, + "msg": { + "description": "思考內容", + "title": "Msg", + "type": "string" + } + }, + "required": [ + "agent", + "msg" + ], + "title": "TerminalThoughtEvent", + "type": "object" + }, + "ActionType": { + "description": "執行類型", + "enum": [ + "kubectl", + "script", + "manual" + ], + "title": "ActionType", + "type": "string" + }, + "PlaybookSource": { + "description": "Playbook 來源", + "enum": [ + "extracted", + "manual" + ], + "title": "PlaybookSource", + "type": "string" + }, + "PlaybookStatus": { + "description": "Playbook 狀態", + "enum": [ + "draft", + "approved", + "deprecated" + ], + "title": "PlaybookStatus", + "type": "string" + }, + "RepairStep": { + "description": "修復步驟\n\n設計: 支援多種執行類型\n- kubectl: Kubernetes 命令\n- script: 腳本執行\n- manual: 需人工操作", + "properties": { + "step_number": { + "description": "步驟序號", + "minimum": 1, + "title": "Step Number", + "type": "integer" + }, + "action_type": { + "$ref": "#/definitions/ActionType" + }, + "command": { + "description": "執行命令或操作描述", + "title": "Command", + "type": "string" + }, + "expected_result": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "預期結果", + "title": "Expected Result" + }, + "rollback_command": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "回滾命令", + "title": "Rollback Command" + }, + "requires_approval": { + "default": false, + "description": "是否需要人工審核", + "title": "Requires Approval", + "type": "boolean" + }, + "risk_level": { + "$ref": "#/definitions/RiskLevel", + "default": "MEDIUM" + } + }, + "required": [ + "step_number", + "action_type", + "command" + ], + "title": "RepairStep", + "type": "object" + }, + "SymptomPattern": { + "description": "症狀模式 - 用於相似度比對\n\n設計: 多維度特徵向量\n- alert_names: 告警名稱集合\n- affected_services: 受影響服務集合\n- severity: 嚴重度\n- labels: Prometheus 標籤 (k8s namespace, deployment, etc.)", + "properties": { + "alert_names": { + "description": "告警名稱模式 (如 HighCPU*, PodCrash*)", + "items": { + "type": "string" + }, + "title": "Alert Names", + "type": "array" + }, + "affected_services": { + "description": "受影響服務模式", + "items": { + "type": "string" + }, + "title": "Affected Services", + "type": "array" + }, + "severity_range": { + "default": [ + "P1", + "P2" + ], + "description": "適用嚴重度範圍", + "items": { + "type": "string" + }, + "title": "Severity Range", + "type": "array" + }, + "label_patterns": { + "additionalProperties": { + "type": "string" + }, + "description": "標籤匹配 (regex)", + "title": "Label Patterns", + "type": "object" + }, + "keywords": { + "description": "關鍵字 (從 annotations 提取)", + "items": { + "type": "string" + }, + "title": "Keywords", + "type": "array" + } + }, + "title": "SymptomPattern", + "type": "object" + }, + "Playbook": { + "description": "Playbook - 修復劇本\n\n三層記憶位置:\n- Working Memory (Redis): playbook:{playbook_id} TTL 7天\n- Episodic Memory (PostgreSQL): playbooks 表\n- Semantic Memory (Vector DB): 向量化症狀特徵 (Phase 8+)\n\n設計遵循:\n- ADR-003 leWOOOgo 模組化架構\n- ADR-007 資料保留策略", + "properties": { + "playbook_id": { + "description": "Playbook 唯一識別碼", + "title": "Playbook Id", + "type": "string" + }, + "name": { + "description": "Playbook 名稱 (人類可讀)", + "title": "Name", + "type": "string" + }, + "description": { + "description": "問題描述與修復策略摘要", + "title": "Description", + "type": "string" + }, + "status": { + "$ref": "#/definitions/PlaybookStatus", + "default": "draft" + }, + "source": { + "$ref": "#/definitions/PlaybookSource", + "default": "extracted" + }, + "symptom_pattern": { + "$ref": "#/definitions/SymptomPattern", + "description": "觸發此 Playbook 的症狀模式" + }, + "repair_steps": { + "description": "修復步驟列表", + "items": { + "$ref": "#/definitions/RepairStep" + }, + "title": "Repair Steps", + "type": "array" + }, + "estimated_duration_minutes": { + "default": 5, + "description": "預估修復時間 (分鐘)", + "maximum": 480, + "minimum": 1, + "title": "Estimated Duration Minutes", + "type": "integer" + }, + "source_incident_ids": { + "description": "萃取來源的 Incident ID", + "items": { + "type": "string" + }, + "title": "Source Incident Ids", + "type": "array" + }, + "ai_confidence": { + "default": 0.0, + "description": "AI 萃取信心度", + "maximum": 1.0, + "minimum": 0.0, + "title": "Ai Confidence", + "type": "number" + }, + "success_count": { + "default": 0, + "description": "成功執行次數", + "minimum": 0, + "title": "Success Count", + "type": "integer" + }, + "failure_count": { + "default": 0, + "description": "失敗執行次數", + "minimum": 0, + "title": "Failure Count", + "type": "integer" + }, + "last_used_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "最後使用時間", + "title": "Last Used At" + }, + "approved_by": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "核准者", + "title": "Approved By" + }, + "approved_at": { + "anyOf": [ + { + "format": "date-time", + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "核准時間", + "title": "Approved At" + }, + "tags": { + "description": "標籤", + "items": { + "type": "string" + }, + "title": "Tags", + "type": "array" + }, + "notes": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "人工補充說明", + "title": "Notes" + }, + "created_at": { + "format": "date-time", + "title": "Created At", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "title": "Updated At", + "type": "string" + } + }, + "required": [ + "name", + "description" + ], + "title": "Playbook", + "type": "object" + }, + "PlaybookResponse": { + "description": "單一 Playbook 回應", + "properties": { + "playbook": { + "$ref": "#/definitions/Playbook" + }, + "success_rate": { + "maximum": 1.0, + "minimum": 0.0, + "title": "Success Rate", + "type": "number" + }, + "is_high_quality": { + "title": "Is High Quality", + "type": "boolean" + } + }, + "required": [ + "playbook", + "success_rate", + "is_high_quality" + ], + "title": "PlaybookResponse", + "type": "object" + }, + "PlaybookListResponse": { + "description": "Playbook 列表回應", + "properties": { + "items": { + "items": { + "$ref": "#/definitions/PlaybookResponse" + }, + "title": "Items", + "type": "array" + }, + "total": { + "title": "Total", + "type": "integer" + }, + "limit": { + "title": "Limit", + "type": "integer" + }, + "offset": { + "title": "Offset", + "type": "integer" + } + }, + "required": [ + "items", + "total", + "limit", + "offset" + ], + "title": "PlaybookListResponse", + "type": "object" + }, + "PlaybookCreateRequest": { + "description": "建立 Playbook 請求 (人工建立)", + "properties": { + "name": { + "maxLength": 256, + "minLength": 1, + "title": "Name", + "type": "string" + }, + "description": { + "maxLength": 2000, + "minLength": 1, + "title": "Description", + "type": "string" + }, + "symptom_pattern": { + "$ref": "#/definitions/SymptomPattern" + }, + "repair_steps": { + "items": { + "$ref": "#/definitions/RepairStep" + }, + "minItems": 1, + "title": "Repair Steps", + "type": "array" + }, + "estimated_duration_minutes": { + "default": 5, + "maximum": 480, + "minimum": 1, + "title": "Estimated Duration Minutes", + "type": "integer" + }, + "tags": { + "items": { + "type": "string" + }, + "title": "Tags", + "type": "array" + }, + "notes": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Notes" + } + }, + "required": [ + "name", + "description", + "symptom_pattern", + "repair_steps" + ], + "title": "PlaybookCreateRequest", + "type": "object" + }, + "PlaybookUpdateRequest": { + "description": "更新 Playbook 請求", + "properties": { + "name": { + "anyOf": [ + { + "maxLength": 256, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Name" + }, + "description": { + "anyOf": [ + { + "maxLength": 2000, + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Description" + }, + "symptom_pattern": { + "anyOf": [ + { + "$ref": "#/definitions/SymptomPattern" + }, + { + "type": "null" + } + ], + "default": null + }, + "repair_steps": { + "anyOf": [ + { + "items": { + "$ref": "#/definitions/RepairStep" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Repair Steps" + }, + "estimated_duration_minutes": { + "anyOf": [ + { + "maximum": 480, + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Estimated Duration Minutes" + }, + "tags": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Tags" + }, + "notes": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "title": "Notes" + }, + "status": { + "anyOf": [ + { + "$ref": "#/definitions/PlaybookStatus" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "title": "PlaybookUpdateRequest", + "type": "object" + }, + "PlaybookRecommendation": { + "description": "Playbook 推薦結果", + "properties": { + "playbook": { + "$ref": "#/definitions/Playbook" + }, + "similarity_score": { + "description": "相似度分數", + "maximum": 1.0, + "minimum": 0.0, + "title": "Similarity Score", + "type": "number" + }, + "matched_symptoms": { + "description": "匹配的症狀", + "items": { + "type": "string" + }, + "title": "Matched Symptoms", + "type": "array" + }, + "reason": { + "description": "推薦原因", + "title": "Reason", + "type": "string" + } + }, + "required": [ + "playbook", + "similarity_score", + "reason" + ], + "title": "PlaybookRecommendation", + "type": "object" + }, + "CSRFTokenResponse": { + "description": "CSRF Token 回應模型", + "example": { + "cookie_name": "awoooi_csrf_token", + "header_name": "X-CSRF-Token", + "token": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234abcd" + }, + "properties": { + "token": { + "description": "CSRF Token (64 字元十六進位)", + "maxLength": 64, + "minLength": 64, + "title": "Token", + "type": "string" + }, + "cookie_name": { + "default": "awoooi_csrf_token", + "description": "Cookie 名稱", + "title": "Cookie Name", + "type": "string" + }, + "header_name": { + "default": "X-CSRF-Token", + "description": "Header 名稱 (敏感請求時使用)", + "title": "Header Name", + "type": "string" + } + }, + "required": [ + "token" + ], + "title": "CSRFTokenResponse", + "type": "object" + } + } +} \ No newline at end of file diff --git a/packages/shared-types/src/api-types.ts b/packages/shared-types/src/api-types.ts new file mode 100644 index 00000000..b4f3f179 --- /dev/null +++ b/packages/shared-types/src/api-types.ts @@ -0,0 +1,1352 @@ +/* Auto-generated from Pydantic models - DO NOT EDIT */ + +/** + * 授權請求狀態機 + * + * PENDING → APPROVED → EXECUTION_SUCCESS + * → EXECUTION_FAILED + * PENDING → REJECTED + * PENDING → EXPIRED + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "ApprovalStatus". + */ +export type ApprovalStatus = "pending" | "approved" | "rejected" | "expired" | "execution_success" | "execution_failed"; +export type AffectedPods = number; +export type EstimatedDowntime = string; +export type RelatedServices = string[]; +/** + * 資料影響類型 + */ +export type DataImpact = "none" | "read_only" | "write" | "destructive"; +/** + * 資料影響類型 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "DataImpact". + */ +export type DataImpact1 = "none" | "read_only" | "write" | "destructive"; +export type Name = string; +export type Passed = boolean; +export type Message = string | null; +/** + * 風險等級 - 決定所需簽核人數 + * + * - LOW: 0 人,自動放行 + * - MEDIUM: 需 1 人簽核 + * - HIGH: 需 1 人簽核 (信任引擎可降級至 MEDIUM) + * - CRITICAL: 需 2 人 Multi-Sig 雙重簽核 (永不降級) + * + * 變更紀錄: + * - 2026-03-25: 新增 HIGH (Phase 16 R2 合併自 trust_engine.py) + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "RiskLevel". + */ +export type RiskLevel = "low" | "medium" | "high" | "critical"; +export type Id = string; +/** + * 簽核者 ID + */ +export type SignerId = string; +/** + * 簽核者名稱 + */ +export type SignerName = string; +export type SignedAt = string; +export type Comment = string | null; +/** + * 簽核來源通道 (web/telegram/api/system) + */ +export type SignatureSource = "web" | "telegram" | "api" | "system"; +/** + * Telegram User ID (永久追溯憑證) + */ +export type TelegramUserId = number | null; +/** + * Telegram 訊息 ID + */ +export type TelegramMessageId = number | null; +/** + * 簽核來源通道 (Phase 5.4.5: AuditLog 擴充) + * + * 用於追溯簽核是從哪個通道發起 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "SignatureSource". + */ +export type SignatureSource1 = "web" | "telegram" | "api" | "system"; +/** + * 執行動作描述 + */ +export type Action = string; +/** + * 詳細說明 + */ +export type Description = string; +/** + * 風險等級 + */ +export type RiskLevel1 = "low" | "medium" | "high" | "critical"; +export type DryRunChecks = DryRunCheck[]; +/** + * 請求發起者 + */ +export type RequestedBy = string; +/** + * 到期時間 + */ +export type ExpiresAt = string | null; +/** + * 額外元資料 + */ +export type Metadata = { + [k: string]: unknown; +} | null; +export type Id1 = string; +/** + * 授權請求狀態機 + * + * PENDING → APPROVED → EXECUTION_SUCCESS + * → EXECUTION_FAILED + * PENDING → REJECTED + * PENDING → EXPIRED + */ +export type ApprovalStatus1 = + | "pending" + | "approved" + | "rejected" + | "expired" + | "execution_success" + | "execution_failed"; +/** + * 所需簽核數 + */ +export type RequiredSignatures = number; +export type Signatures = Signature[]; +export type CreatedAt = string; +export type UpdatedAt = string; +/** + * 解決時間 + */ +export type ResolvedAt = string | null; +export type RejectionReason = string | null; +/** + * 告警指紋 Hash + */ +export type Fingerprint = string | null; +/** + * 聚合觸發次數 + */ +export type HitCount = number; +/** + * 最後觸發時間 + */ +export type LastSeenAt = string; +/** + * 執行動作描述 + */ +export type Action1 = string; +/** + * 詳細說明 + */ +export type Description1 = string; +/** + * 風險等級 + */ +export type RiskLevel2 = "low" | "medium" | "high" | "critical"; +export type DryRunChecks1 = DryRunCheck[]; +/** + * 請求發起者 + */ +export type RequestedBy1 = string; +/** + * 到期時間 + */ +export type ExpiresAt1 = string | null; +/** + * 額外元資料 + */ +export type Metadata1 = { + [k: string]: unknown; +} | null; +export type Id2 = string; +export type Action2 = string; +export type Description2 = string; +export type DryRunChecks2 = DryRunCheck[]; +export type RequiredSignatures1 = number; +export type CurrentSignatures = number; +export type Signatures1 = Signature[]; +export type RequestedBy2 = string; +export type CreatedAt1 = string; +export type ExpiresAt2 = string | null; +export type ResolvedAt1 = string | null; +export type Fingerprint1 = string | null; +export type HitCount1 = number; +export type LastSeenAt1 = string | null; +export type Metadata2 = { + [k: string]: unknown; +} | null; +export type Count = number; +export type Approvals = ApprovalRequestResponse[]; +/** + * 退回者 ID + */ +export type RejectorId = string; +/** + * 退回者名稱 + */ +export type RejectorName = string; +/** + * 退回原因 + */ +export type Reason = string; +/** + * 簽核者 ID + */ +export type SignerId1 = string; +/** + * 簽核者名稱 + */ +export type SignerName1 = string; +/** + * 簽核備註 + */ +export type Comment1 = string | null; +export type Success = boolean; +export type Message1 = string; +/** + * 是否觸發執行 (當簽核數滿足時) + */ +export type ExecutionTriggered = boolean; +/** + * 觸發此推論的告警 ID 列表 + */ +export type InputSignalIds = string[]; +/** + * 從記憶中檢索的上下文摘要 + */ +export type ContextRetrieved = string[]; +/** + * 使用的 AI 模型 (如 ollama/llama3.2:latest, gemini/gemini-pro) + */ +export type ModelUsed = string; +/** + * Prompt 模板版本號 + */ +export type PromptTemplateVersion = string; +/** + * AI 的根因推論 + */ +export type Hypothesis = string; +/** + * 信心指數 (0.0 - 1.0) + */ +export type Confidence = number; +/** + * 推理步驟 (可解釋性) + */ +export type ReasoningSteps = string[]; +/** + * 可能的根本原因列表 + */ +export type ProbableRootCauses = string[]; +/** + * 推論開始時間 + */ +export type InferenceStartedAt = string; +/** + * 推論完成時間 + */ +export type InferenceCompletedAt = string; +/** + * 推論延遲 (毫秒) + */ +export type LatencyMs = number; +/** + * 異常簽名 Hash (前 16 字元) + */ +export type AnomalyKey = string; +/** + * 1 小時內發生次數 + */ +export type Count1H = number; +/** + * 24 小時內發生次數 + */ +export type Count24H = number; +/** + * 7 天內發生次數 + */ +export type Count7D = number; +/** + * 30 天內發生次數 + */ +export type Count30D = number; +/** + * 升級建議 (基於 24h 頻率) + */ +export type EscalationLevel = ("REPEAT" | "ESCALATE" | "PERMANENT_FIX") | null; +/** + * 自動修復嘗試次數 + */ +export type AutoRepairCount = number; +/** + * 最後一次修復動作 + */ +export type LastRepairAction = string | null; +/** + * 最後一次修復是否成功 + */ +export type LastRepairSuccess = boolean | null; +/** + * 是否已執行修復提案 + */ +export type ProposalExecuted = boolean; +/** + * 執行是否成功 (None = 未執行) + */ +export type ExecutionSuccess = boolean | null; +/** + * 實際停機時間 (分鐘) + */ +export type ActualDowntimeMinutes = number | null; +/** + * 人類的文字回饋 (如 '這個建議很準' 或 '下次應該先檢查 X') + */ +export type HumanFeedback = string | null; +/** + * 有效性評分 (1-5 分) + */ +export type EffectivenessScore = number | null; +/** + * 是否納入長期記憶 (Episodic Memory) + */ +export type ShouldRemember = boolean; +/** + * 給未來 AI 的學習筆記 + */ +export type LearningNotes = string | null; +/** + * 事件狀態機 + * + * INVESTIGATING → MITIGATING → RESOLVED → CLOSED + * ↘ (無法解決) → ESCALATED + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "IncidentStatus". + */ +export type IncidentStatus = "investigating" | "mitigating" | "resolved" | "closed" | "escalated"; +/** + * 事件嚴重度 (Incident Severity) + * + * 與 RiskLevel 的區別: + * - Severity: 事件本身的嚴重程度 (P0 最嚴重) + * - RiskLevel: 修復操作的風險等級 (CRITICAL 最危險) + * + * 用於: + * - AI 分層調用策略 (P0 直接用 Claude,P2/P3 用 Ollama) + * - SLA 響應時間門檻 + * - 告警通知優先級 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "Severity". + */ +export type Severity = "P0" | "P1" | "P2" | "P3"; +/** + * 信號唯一識別碼 (8 字元) + */ +export type SignalId = string; +/** + * 告警名稱 (如 HighCPUUsage) + */ +export type AlertName = string; +/** + * 告警嚴重度 + */ +export type Severity1 = "P0" | "P1" | "P2" | "P3"; +/** + * 告警來源 + */ +export type Source = "prometheus" | "signoz" | "alertmanager" | "manual" | "telegram"; +/** + * 告警觸發時間 + */ +export type FiredAt = string; +/** + * 告警解除時間 + */ +export type ResolvedAt2 = string | null; +/** + * 告警指紋 Hash,用於去重與聚合 + */ +export type Fingerprint2 = string | null; +/** + * 事件唯一識別碼 (如 INC-20260322-A1B2C3) + */ +export type IncidentId = string; +/** + * 事件狀態 + */ +export type IncidentStatus1 = "investigating" | "mitigating" | "resolved" | "closed" | "escalated"; +/** + * 事件嚴重度 + */ +export type Severity2 = "P0" | "P1" | "P2" | "P3"; +/** + * 關聯的告警信號列表 + */ +export type Signals = Signal[]; +/** + * 受影響的服務列表 (GraphRAG Blast Radius) + */ +export type AffectedServices = string[]; +/** + * 關聯的 ApprovalRequest ID 列表 (支援多重決策軌跡) + */ +export type ProposalIds = string[]; +/** + * 事件建立時間 + */ +export type CreatedAt2 = string; +/** + * 最後更新時間 + */ +export type UpdatedAt1 = string; +/** + * 事件解決時間 + */ +export type ResolvedAt3 = string | null; +/** + * 事件關閉時間 (含回饋) + */ +export type ClosedAt = string | null; +/** + * Working Memory TTL (天) + */ +export type TtlDays = number; +/** + * 是否已固化到 PostgreSQL (Episodic Memory) + */ +export type PersistedToPg = boolean; +/** + * 是否已向量化到 Vector DB (Semantic Memory) + */ +export type Vectorized = boolean; +export type Signals1 = Signal[]; +export type AffectedServices1 = string[]; +export type IncidentId1 = string; +export type Signals2 = Signal[]; +export type AffectedServices2 = string[]; +export type ProposalIds1 = string[]; +export type CreatedAt3 = string; +export type UpdatedAt2 = string; +export type ResolvedAt4 = string | null; +export type ClosedAt1 = string | null; +export type AffectedServices3 = string[] | null; +/** + * 統帥當前所在的路由 + */ +export type CurrentPage = string; +/** + * 正在檢視的實體 ID (incident/approval) + */ +export type FocusedEntityId = string | null; +/** + * 統帥輸入的原始指令或意圖 + */ +export type Intent = string; +/** + * 現有 Session ID (用於續傳) + */ +export type SessionId = string | null; +/** + * Session UUID + */ +export type SessionId1 = string; +/** + * SSE 串流訂閱 URL + */ +export type StreamUrl = string; +export type CreatedAt4 = string; +/** + * Terminal Session 狀態 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "TerminalSessionStatus". + */ +export type TerminalSessionStatus = "pending" | "processing" | "completed" | "aborted" | "error"; +export type SessionId2 = string; +export type CreatedAt5 = string; +export type LastEventId = number; +export type MessageCount = number; +/** + * 中斷原因 + */ +export type Reason1 = string | null; +export type SessionId3 = string; +export type Aborted = boolean; +export type Message2 = string; +/** + * 代理人名稱 + */ +export type Agent = string; +/** + * 思考內容 + */ +export type Msg = string; +/** + * 執行類型 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "ActionType". + */ +export type ActionType = "kubectl" | "script" | "manual"; +/** + * Playbook 來源 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PlaybookSource". + */ +export type PlaybookSource = "extracted" | "manual"; +/** + * Playbook 狀態 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PlaybookStatus". + */ +export type PlaybookStatus = "draft" | "approved" | "deprecated"; +/** + * 步驟序號 + */ +export type StepNumber = number; +/** + * 執行命令或操作描述 + */ +export type Command = string; +/** + * 預期結果 + */ +export type ExpectedResult = string | null; +/** + * 回滾命令 + */ +export type RollbackCommand = string | null; +/** + * 是否需要人工審核 + */ +export type RequiresApproval = boolean; +/** + * 風險等級 - 決定所需簽核人數 + * + * - LOW: 0 人,自動放行 + * - MEDIUM: 需 1 人簽核 + * - HIGH: 需 1 人簽核 (信任引擎可降級至 MEDIUM) + * - CRITICAL: 需 2 人 Multi-Sig 雙重簽核 (永不降級) + * + * 變更紀錄: + * - 2026-03-25: 新增 HIGH (Phase 16 R2 合併自 trust_engine.py) + */ +export type RiskLevel3 = "low" | "medium" | "high" | "critical"; +/** + * 告警名稱模式 (如 HighCPU*, PodCrash*) + */ +export type AlertNames = string[]; +/** + * 受影響服務模式 + */ +export type AffectedServices4 = string[]; +/** + * 適用嚴重度範圍 + */ +export type SeverityRange = string[]; +/** + * 關鍵字 (從 annotations 提取) + */ +export type Keywords = string[]; +/** + * Playbook 唯一識別碼 + */ +export type PlaybookId = string; +/** + * Playbook 名稱 (人類可讀) + */ +export type Name1 = string; +/** + * 問題描述與修復策略摘要 + */ +export type Description3 = string; +/** + * Playbook 狀態 + */ +export type PlaybookStatus1 = "draft" | "approved" | "deprecated"; +/** + * Playbook 來源 + */ +export type PlaybookSource1 = "extracted" | "manual"; +/** + * 修復步驟列表 + */ +export type RepairSteps = RepairStep[]; +/** + * 預估修復時間 (分鐘) + */ +export type EstimatedDurationMinutes = number; +/** + * 萃取來源的 Incident ID + */ +export type SourceIncidentIds = string[]; +/** + * AI 萃取信心度 + */ +export type AiConfidence = number; +/** + * 成功執行次數 + */ +export type SuccessCount = number; +/** + * 失敗執行次數 + */ +export type FailureCount = number; +/** + * 最後使用時間 + */ +export type LastUsedAt = string | null; +/** + * 核准者 + */ +export type ApprovedBy = string | null; +/** + * 核准時間 + */ +export type ApprovedAt = string | null; +/** + * 標籤 + */ +export type Tags = string[]; +/** + * 人工補充說明 + */ +export type Notes = string | null; +export type CreatedAt6 = string; +export type UpdatedAt3 = string; +export type SuccessRate = number; +export type IsHighQuality = boolean; +export type Items = PlaybookResponse[]; +export type Total = number; +export type Limit = number; +export type Offset = number; +export type Name2 = string; +export type Description4 = string; +/** + * @minItems 1 + */ +export type RepairSteps1 = [RepairStep, ...RepairStep[]]; +export type EstimatedDurationMinutes1 = number; +export type Tags1 = string[]; +export type Notes1 = string | null; +export type Name3 = string | null; +export type Description5 = string | null; +export type RepairSteps2 = RepairStep[] | null; +export type EstimatedDurationMinutes2 = number | null; +export type Tags2 = string[] | null; +export type Notes2 = string | null; +/** + * 相似度分數 + */ +export type SimilarityScore = number; +/** + * 匹配的症狀 + */ +export type MatchedSymptoms = string[]; +/** + * 推薦原因 + */ +export type Reason2 = string; +/** + * CSRF Token (64 字元十六進位) + */ +export type Token = string; +/** + * Cookie 名稱 + */ +export type CookieName = string; +/** + * Header 名稱 (敏感請求時使用) + */ +export type HeaderName = string; + +/** + * Auto-generated from Pydantic models - DO NOT EDIT + */ +export interface AWOOOIAPITypes { + [k: string]: unknown; +} +/** + * 爆炸半徑 - 影響範圍評估 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "BlastRadius". + */ +export interface BlastRadius { + affected_pods?: AffectedPods; + estimated_downtime?: EstimatedDowntime; + related_services?: RelatedServices; + data_impact?: DataImpact; + [k: string]: unknown; +} +/** + * Dry-Run 預演檢查結果 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "DryRunCheck". + */ +export interface DryRunCheck { + name: Name; + passed: Passed; + message?: Message; + [k: string]: unknown; +} +/** + * 簽核記錄 + * + * Phase 5.4.5: 新增 Telegram 審計欄位 + * - source: 簽核來源通道 + * - telegram_user_id: Telegram User ID (永久追溯憑證) + * - telegram_message_id: Telegram 訊息 ID + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "Signature". + */ +export interface Signature { + id?: Id; + signer_id: SignerId; + signer_name: SignerName; + signed_at?: SignedAt; + comment?: Comment; + source?: SignatureSource; + telegram_user_id?: TelegramUserId; + telegram_message_id?: TelegramMessageId; + [k: string]: unknown; +} +/** + * 完整授權請求模型 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "ApprovalRequest". + */ +export interface ApprovalRequest { + action: Action; + description: Description; + risk_level: RiskLevel1; + blast_radius?: BlastRadius; + dry_run_checks?: DryRunChecks; + requested_by: RequestedBy; + expires_at?: ExpiresAt; + metadata?: Metadata; + id?: Id1; + status?: ApprovalStatus1; + required_signatures: RequiredSignatures; + signatures?: Signatures; + created_at?: CreatedAt; + updated_at?: UpdatedAt; + resolved_at?: ResolvedAt; + rejection_reason?: RejectionReason; + fingerprint?: Fingerprint; + hit_count?: HitCount; + last_seen_at?: LastSeenAt; + [k: string]: unknown; +} +/** + * 建立授權請求 (API 輸入) + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "ApprovalRequestCreate". + */ +export interface ApprovalRequestCreate { + action: Action1; + description: Description1; + risk_level: RiskLevel2; + blast_radius?: BlastRadius; + dry_run_checks?: DryRunChecks1; + requested_by: RequestedBy1; + expires_at?: ExpiresAt1; + metadata?: Metadata1; + [k: string]: unknown; +} +/** + * 授權請求 API 回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "ApprovalRequestResponse". + */ +export interface ApprovalRequestResponse { + id: Id2; + action: Action2; + description: Description2; + status: ApprovalStatus; + risk_level: RiskLevel; + blast_radius: BlastRadius; + dry_run_checks: DryRunChecks2; + required_signatures: RequiredSignatures1; + current_signatures: CurrentSignatures; + signatures: Signatures1; + requested_by: RequestedBy2; + created_at: CreatedAt1; + expires_at: ExpiresAt2; + resolved_at: ResolvedAt1; + fingerprint?: Fingerprint1; + hit_count?: HitCount1; + last_seen_at?: LastSeenAt1; + metadata?: Metadata2; + [k: string]: unknown; +} +/** + * 待簽核清單回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PendingApprovalsResponse". + */ +export interface PendingApprovalsResponse { + count: Count; + approvals: Approvals; + [k: string]: unknown; +} +/** + * 退回請求 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "RejectRequest". + */ +export interface RejectRequest { + rejector_id: RejectorId; + rejector_name: RejectorName; + reason: Reason; + [k: string]: unknown; +} +/** + * 簽核請求 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "SignRequest". + */ +export interface SignRequest { + signer_id: SignerId1; + signer_name: SignerName1; + comment?: Comment1; + [k: string]: unknown; +} +/** + * 簽核回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "SignResponse". + */ +export interface SignResponse { + success: Success; + message: Message1; + approval: ApprovalRequestResponse; + execution_triggered?: ExecutionTriggered; + [k: string]: unknown; +} +/** + * AI 決策鏈 - 完整記錄推論過程,供稽核使用 + * + * CISO 要求: + * - 必須記錄 AI 使用的模型、Prompt 版本 + * - 必須記錄推理步驟 (可解釋性) + * - 必須記錄推論延遲 (效能監控) + * + * 用於回答: + * - 「AI 為什麼做出這個建議?」 + * - 「AI 當時參考了哪些資料?」 + * - 「這個決策可以被重現嗎?」 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "AIDecisionChain". + */ +export interface AIDecisionChain { + input_signal_ids?: InputSignalIds; + context_retrieved?: ContextRetrieved; + model_used: ModelUsed; + prompt_template_version?: PromptTemplateVersion; + hypothesis: Hypothesis; + confidence: Confidence; + reasoning_steps?: ReasoningSteps; + /** + * 爆炸半徑分析結果 (復用現有模型) + */ + blast_radius?: BlastRadius | null; + probable_root_causes?: ProbableRootCauses; + inference_started_at: InferenceStartedAt; + inference_completed_at: InferenceCompletedAt; + latency_ms: LatencyMs; + [k: string]: unknown; +} +/** + * 事件頻率統計 - ADR-037 監控增強架構 + * + * 2026-03-29 ogt: 統帥指示「重啟只是治標,太常發生的異常必須徹底解決」 + * + * 用途: + * - 統計同一異常在不同時間窗口內的發生次數 + * - 根據頻率決定修復策略的升級 (Tier 1→4) + * - 讓使用者知道這個問題有多頻繁 + * + * 升級閾值: + * - REPEAT: ≥ 3 次/24h (標記重複) + * - ESCALATE: ≥ 5 次/24h (升級 Tier,通知 Owner) + * - PERMANENT_FIX: ≥ 10 次/24h (強制根因修復) + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "IncidentFrequencyStats". + */ +export interface IncidentFrequencyStats { + anomaly_key: AnomalyKey; + count_1h?: Count1H; + count_24h?: Count24H; + count_7d?: Count7D; + count_30d?: Count30D; + escalation_level?: EscalationLevel; + auto_repair_count?: AutoRepairCount; + last_repair_action?: LastRepairAction; + last_repair_success?: LastRepairSuccess; + [k: string]: unknown; +} +/** + * 事件結果 - AI 學習的關鍵回饋 + * + * CPO 要求: + * - 必須記錄執行結果 (成功/失敗) + * - 必須收集人類回饋 (AI 建議是否有效) + * - 必須標記是否納入長期記憶 + * + * 這是讓 AI 「從經驗中學習」的關鍵: + * - 如果 AI 的建議有效 → 強化這個模式 + * - 如果 AI 的建議無效 → 記錄為負面案例 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "IncidentOutcome". + */ +export interface IncidentOutcome { + proposal_executed?: ProposalExecuted; + execution_success?: ExecutionSuccess; + actual_downtime_minutes?: ActualDowntimeMinutes; + human_feedback?: HumanFeedback; + effectiveness_score?: EffectivenessScore; + should_remember?: ShouldRemember; + learning_notes?: LearningNotes; + [k: string]: unknown; +} +/** + * 原始告警信號 - 從 Prometheus/SignOz/Alertmanager 接收 + * + * 這是 Incident 的「感知輸入」,一個 Incident 可能包含多個 Signal。 + * 例如: CPU Spike + Memory OOM + Pod Restart 三個告警可能屬於同一個 Incident。 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "Signal". + */ +export interface Signal { + signal_id?: SignalId; + alert_name: AlertName; + severity: Severity1; + source: Source; + fired_at: FiredAt; + resolved_at?: ResolvedAt2; + labels?: Labels; + annotations?: Annotations; + fingerprint?: Fingerprint2; + [k: string]: unknown; +} +/** + * Prometheus 標籤 (如 pod, namespace, service) + */ +export interface Labels { + [k: string]: string; +} +/** + * 告警附加資訊 (如 summary, description) + */ +export interface Annotations { + [k: string]: string; +} +/** + * 事件模型 - AWOOOI 認知系統的核心資料結構 + * + * 這是 AWOOOI 2.0「認知覺醒計畫」的基石,承載了: + * - 感知 (Signals): 原始告警 + * - 認知 (Decision Chain): AI 推論過程 + * - 決策 (Proposals): 修復建議 + * - 記憶 (Outcome): 結果回饋 + * + * 三層記憶架構: + * ┌─────────────────┐ + * │ Working Memory │ ← Redis Hash, 7 天 TTL + * │ (活躍事件) │ + * └────────┬────────┘ + * │ 定期遷移 + * ▼ + * ┌─────────────────┐ + * │ Episodic Memory │ ← PostgreSQL, 永久保留 + * │ (歷史事件) │ + * └────────┬────────┘ + * │ 向量化 + * ▼ + * ┌─────────────────┐ + * │ Semantic Memory │ ← Vector DB, RAG 檢索 + * │ (知識庫) │ + * └─────────────────┘ + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "Incident". + */ +export interface Incident { + incident_id?: IncidentId; + status?: IncidentStatus1; + severity: Severity2; + signals?: Signals; + affected_services?: AffectedServices; + /** + * AI 決策鏈 (完整推論過程) + */ + decision_chain?: AIDecisionChain | null; + proposal_ids?: ProposalIds; + /** + * 事件結果與人類回饋 + */ + outcome?: IncidentOutcome | null; + /** + * 異常頻率統計 (用於 Tier 分級修復策略) + */ + frequency_stats?: IncidentFrequencyStats | null; + created_at?: CreatedAt2; + updated_at?: UpdatedAt1; + resolved_at?: ResolvedAt3; + closed_at?: ClosedAt; + ttl_days?: TtlDays; + persisted_to_pg?: PersistedToPg; + vectorized?: Vectorized; + [k: string]: unknown; +} +/** + * 建立事件的 DTO + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "IncidentCreate". + */ +export interface IncidentCreate { + severity: Severity; + signals?: Signals1; + affected_services?: AffectedServices1; + [k: string]: unknown; +} +/** + * 事件 API 回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "IncidentResponse". + */ +export interface IncidentResponse { + incident_id: IncidentId1; + status: IncidentStatus; + severity: Severity; + signals: Signals2; + affected_services: AffectedServices2; + decision_chain: AIDecisionChain | null; + proposal_ids: ProposalIds1; + outcome: IncidentOutcome | null; + created_at: CreatedAt3; + updated_at: UpdatedAt2; + resolved_at: ResolvedAt4; + closed_at: ClosedAt1; + [k: string]: unknown; +} +/** + * 更新事件的 DTO + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "IncidentUpdate". + */ +export interface IncidentUpdate { + status?: IncidentStatus | null; + severity?: Severity | null; + affected_services?: AffectedServices3; + decision_chain?: AIDecisionChain | null; + outcome?: IncidentOutcome | null; + [k: string]: unknown; +} +/** + * 空間感知上下文 (Ghost Payload) + * + * 前端隱形夾帶,讓 AI 知道使用者正在看什麼 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "SpatialContext". + */ +export interface SpatialContext { + current_page: CurrentPage; + focused_entity_id?: FocusedEntityId; + [k: string]: unknown; +} +/** + * Terminal Intent 請求 + * + * 統帥輸入的指令或問題 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "TerminalIntentRequest". + */ +export interface TerminalIntentRequest { + intent: Intent; + context: SpatialContext1; + session_id?: SessionId; + [k: string]: unknown; +} +/** + * 前端空間感知上下文 + */ +export interface SpatialContext1 { + current_page: CurrentPage; + focused_entity_id?: FocusedEntityId; + [k: string]: unknown; +} +/** + * Intent 請求回應 + * + * 返回 session_id 供前端訂閱 SSE + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "TerminalIntentResponse". + */ +export interface TerminalIntentResponse { + session_id: SessionId1; + stream_url: StreamUrl; + created_at?: CreatedAt4; + [k: string]: unknown; +} +/** + * Session 狀態查詢回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "TerminalStatusResponse". + */ +export interface TerminalStatusResponse { + session_id: SessionId2; + status: TerminalSessionStatus; + created_at: CreatedAt5; + last_event_id: LastEventId; + message_count: MessageCount; + [k: string]: unknown; +} +/** + * 中斷執行請求 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "TerminalAbortRequest". + */ +export interface TerminalAbortRequest { + reason?: Reason1; + [k: string]: unknown; +} +/** + * 中斷執行回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "TerminalAbortResponse". + */ +export interface TerminalAbortResponse { + session_id: SessionId3; + aborted: Aborted; + message: Message2; + [k: string]: unknown; +} +/** + * AI 思考軌跡事件 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "TerminalThoughtEvent". + */ +export interface TerminalThoughtEvent { + agent: Agent; + msg: Msg; + [k: string]: unknown; +} +/** + * 修復步驟 + * + * 設計: 支援多種執行類型 + * - kubectl: Kubernetes 命令 + * - script: 腳本執行 + * - manual: 需人工操作 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "RepairStep". + */ +export interface RepairStep { + step_number: StepNumber; + action_type: ActionType; + command: Command; + expected_result?: ExpectedResult; + rollback_command?: RollbackCommand; + requires_approval?: RequiresApproval; + risk_level?: RiskLevel3; + [k: string]: unknown; +} +/** + * 症狀模式 - 用於相似度比對 + * + * 設計: 多維度特徵向量 + * - alert_names: 告警名稱集合 + * - affected_services: 受影響服務集合 + * - severity: 嚴重度 + * - labels: Prometheus 標籤 (k8s namespace, deployment, etc.) + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "SymptomPattern". + */ +export interface SymptomPattern { + alert_names?: AlertNames; + affected_services?: AffectedServices4; + severity_range?: SeverityRange; + label_patterns?: LabelPatterns; + keywords?: Keywords; + [k: string]: unknown; +} +/** + * 標籤匹配 (regex) + */ +export interface LabelPatterns { + [k: string]: string; +} +/** + * Playbook - 修復劇本 + * + * 三層記憶位置: + * - Working Memory (Redis): playbook:{playbook_id} TTL 7天 + * - Episodic Memory (PostgreSQL): playbooks 表 + * - Semantic Memory (Vector DB): 向量化症狀特徵 (Phase 8+) + * + * 設計遵循: + * - ADR-003 leWOOOgo 模組化架構 + * - ADR-007 資料保留策略 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "Playbook". + */ +export interface Playbook { + playbook_id?: PlaybookId; + name: Name1; + description: Description3; + status?: PlaybookStatus1; + source?: PlaybookSource1; + symptom_pattern?: SymptomPattern1; + repair_steps?: RepairSteps; + estimated_duration_minutes?: EstimatedDurationMinutes; + source_incident_ids?: SourceIncidentIds; + ai_confidence?: AiConfidence; + success_count?: SuccessCount; + failure_count?: FailureCount; + last_used_at?: LastUsedAt; + approved_by?: ApprovedBy; + approved_at?: ApprovedAt; + tags?: Tags; + notes?: Notes; + created_at?: CreatedAt6; + updated_at?: UpdatedAt3; + [k: string]: unknown; +} +/** + * 觸發此 Playbook 的症狀模式 + */ +export interface SymptomPattern1 { + alert_names?: AlertNames; + affected_services?: AffectedServices4; + severity_range?: SeverityRange; + label_patterns?: LabelPatterns; + keywords?: Keywords; + [k: string]: unknown; +} +/** + * 單一 Playbook 回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PlaybookResponse". + */ +export interface PlaybookResponse { + playbook: Playbook; + success_rate: SuccessRate; + is_high_quality: IsHighQuality; + [k: string]: unknown; +} +/** + * Playbook 列表回應 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PlaybookListResponse". + */ +export interface PlaybookListResponse { + items: Items; + total: Total; + limit: Limit; + offset: Offset; + [k: string]: unknown; +} +/** + * 建立 Playbook 請求 (人工建立) + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PlaybookCreateRequest". + */ +export interface PlaybookCreateRequest { + name: Name2; + description: Description4; + symptom_pattern: SymptomPattern; + repair_steps: RepairSteps1; + estimated_duration_minutes?: EstimatedDurationMinutes1; + tags?: Tags1; + notes?: Notes1; + [k: string]: unknown; +} +/** + * 更新 Playbook 請求 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PlaybookUpdateRequest". + */ +export interface PlaybookUpdateRequest { + name?: Name3; + description?: Description5; + symptom_pattern?: SymptomPattern | null; + repair_steps?: RepairSteps2; + estimated_duration_minutes?: EstimatedDurationMinutes2; + tags?: Tags2; + notes?: Notes2; + status?: PlaybookStatus | null; + [k: string]: unknown; +} +/** + * Playbook 推薦結果 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "PlaybookRecommendation". + */ +export interface PlaybookRecommendation { + playbook: Playbook; + similarity_score: SimilarityScore; + matched_symptoms?: MatchedSymptoms; + reason: Reason2; + [k: string]: unknown; +} +/** + * CSRF Token 回應模型 + * + * This interface was referenced by `AWOOOIAPITypes`'s JSON-Schema + * via the `definition` "CSRFTokenResponse". + */ +export interface CSRFTokenResponse { + token: Token; + cookie_name?: CookieName; + header_name?: HeaderName; + [k: string]: unknown; +} diff --git a/packages/shared-types/src/index.ts b/packages/shared-types/src/index.ts new file mode 100644 index 00000000..3dbff697 --- /dev/null +++ b/packages/shared-types/src/index.ts @@ -0,0 +1,16 @@ +/** + * @awoooi/shared-types + * ==================== + * 前後端共用型別定義 + * + * 自動生成自 Pydantic 模型,請勿手動編輯 api-types.ts + * + * 使用方式: + * import type { ApprovalRequest, IncidentResponse } from '@awoooi/shared-types' + * + * 重新生成: + * pnpm --filter @awoooi/shared-types generate + */ + +// 自動生成的 API 型別 (執行 pnpm generate 後產生) +export * from './api-types' diff --git a/packages/shared-types/tsconfig.json b/packages/shared-types/tsconfig.json new file mode 100644 index 00000000..0429b225 --- /dev/null +++ b/packages/shared-types/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "declaration": true, + "declarationMap": true, + "strict": true, + "skipLibCheck": true, + "outDir": "./dist" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 641ca416..93a209e4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: '@awoooi/lewooogo-core': specifier: workspace:* version: link:../../packages/lewooogo-core + '@awoooi/shared-types': + specifier: workspace:^ + version: link:../../packages/shared-types '@sentry/nextjs': specifier: ^10.45.0 version: 10.45.0(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(next@14.1.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(webpack@5.105.4) @@ -149,6 +152,15 @@ importers: specifier: ^1.2.0 version: 1.6.1(@types/node@20.19.37)(terser@5.46.1) + packages/shared-types: + devDependencies: + json-schema-to-typescript: + specifier: ^15.0.0 + version: 15.0.4 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + packages/tsconfig: {} packages: @@ -157,6 +169,10 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -608,6 +624,9 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -1470,6 +1489,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/lodash@4.17.24': + resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} + '@types/mysql@2.15.27': resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} @@ -2825,6 +2847,11 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-typescript@15.0.4: + resolution: {integrity: sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==} + engines: {node: '>=16.0.0'} + hasBin: true + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -4002,6 +4029,12 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -4370,6 +4403,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@jsdevtools/ono@7.1.3': {} + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.9.1 @@ -5207,6 +5242,8 @@ snapshots: '@types/json5@0.0.29': {} + '@types/lodash@4.17.24': {} + '@types/mysql@2.15.27': dependencies: '@types/node': 20.19.37 @@ -6810,6 +6847,18 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-schema-to-typescript@15.0.4: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.24 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.17.23 + minimist: 1.2.8 + prettier: 3.8.1 + tinyglobby: 0.2.15 + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} diff --git a/scripts/generate-schemas.py b/scripts/generate-schemas.py new file mode 100644 index 00000000..d2bbc3e7 --- /dev/null +++ b/scripts/generate-schemas.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 +""" +Pydantic → JSON Schema 生成器 +============================= +Phase 14.3: 共用型別系統 + +功能: +- 從 Pydantic 模型生成 JSON Schema +- 正確處理 Pydantic 2.x 的 $defs 格式 +- 輸出到 packages/shared-types/schemas/ + +使用方式: + cd apps/api + python ../../scripts/generate-schemas.py + +建立: 2026-03-31 (台北時區) +建立者: Claude Code (Phase 14.3) +""" + +import json +import sys +from pathlib import Path +from typing import Any + +# 加入 apps/api/src 到 Python path +api_src = Path(__file__).parent.parent / "apps" / "api" / "src" +sys.path.insert(0, str(api_src)) + +# 輸出目錄 +OUTPUT_DIR = Path(__file__).parent.parent / "packages" / "shared-types" / "schemas" + + +def extract_and_merge_defs(schema: dict[str, Any], all_defs: dict[str, Any]) -> dict[str, Any]: + """ + 從單一模型 schema 中提取 $defs 並合併到全局 $defs + 同時修正 $ref 路徑 + """ + # 提取並合併 $defs + if "$defs" in schema: + for def_name, def_schema in schema["$defs"].items(): + if def_name not in all_defs: + # 遞迴處理巢狀 $defs + cleaned_def = extract_and_merge_defs(def_schema.copy(), all_defs) + all_defs[def_name] = cleaned_def + + # 移除 schema 中的 $defs (已合併到全局) + cleaned_schema = {k: v for k, v in schema.items() if k != "$defs"} + + return cleaned_schema + + +def fix_refs(obj: Any) -> Any: + """遞迴修正所有 $ref 路徑從 #/$defs/X 到 #/definitions/X""" + if isinstance(obj, dict): + result = {} + for key, value in obj.items(): + if key == "$ref" and isinstance(value, str): + # 修正 ref 路徑 + result[key] = value.replace("#/$defs/", "#/definitions/") + else: + result[key] = fix_refs(value) + return result + elif isinstance(obj, list): + return [fix_refs(item) for item in obj] + else: + return obj + + +def generate_schemas(): + """生成所有模型的 JSON Schema""" + + # 確保輸出目錄存在 + OUTPUT_DIR.mkdir(parents=True, exist_ok=True) + + # 收集所有 definitions + all_definitions: dict[str, Any] = {} + model_count = 0 + + print("📦 Approval Models:") + # === Approval Models === + try: + from models.approval import ( + ApprovalRequest, + ApprovalRequestCreate, + ApprovalRequestResponse, + BlastRadius, + DryRunCheck, + PendingApprovalsResponse, + RejectRequest, + Signature, + SignRequest, + SignResponse, + ) + + approval_models = [ + ApprovalRequest, + ApprovalRequestCreate, + ApprovalRequestResponse, + BlastRadius, + DryRunCheck, + PendingApprovalsResponse, + RejectRequest, + Signature, + SignRequest, + SignResponse, + ] + + for model in approval_models: + schema = model.model_json_schema() + cleaned = extract_and_merge_defs(schema, all_definitions) + all_definitions[model.__name__] = cleaned + model_count += 1 + print(f" ✓ {model.__name__}") + + except ImportError as e: + print(f" ⚠ Import failed: {e}") + + print("\n📦 Incident Models:") + # === Incident Models === + try: + from models.incident import ( + AIDecisionChain, + Incident, + IncidentCreate, + IncidentOutcome, + IncidentResponse, + IncidentUpdate, + Signal, + ) + + incident_models = [ + AIDecisionChain, + Incident, + IncidentCreate, + IncidentOutcome, + IncidentResponse, + IncidentUpdate, + Signal, + ] + + for model in incident_models: + schema = model.model_json_schema() + cleaned = extract_and_merge_defs(schema, all_definitions) + all_definitions[model.__name__] = cleaned + model_count += 1 + print(f" ✓ {model.__name__}") + + except ImportError as e: + print(f" ⚠ Import failed: {e}") + + print("\n📦 Terminal Models:") + # === Terminal Models === + try: + from models.terminal import ( + SpatialContext, + TerminalAbortRequest, + TerminalAbortResponse, + TerminalIntentRequest, + TerminalIntentResponse, + TerminalStatusResponse, + TerminalThoughtEvent, + ) + + terminal_models = [ + TerminalIntentRequest, + TerminalIntentResponse, + TerminalStatusResponse, + TerminalAbortRequest, + TerminalAbortResponse, + TerminalThoughtEvent, + SpatialContext, + ] + + for model in terminal_models: + schema = model.model_json_schema() + cleaned = extract_and_merge_defs(schema, all_definitions) + all_definitions[model.__name__] = cleaned + model_count += 1 + print(f" ✓ {model.__name__}") + + except ImportError as e: + print(f" ⚠ Import failed: {e}") + + print("\n📦 Playbook Models:") + # === Playbook Models === + try: + from models.playbook import ( + Playbook, + PlaybookCreateRequest, + PlaybookListResponse, + PlaybookRecommendation, + PlaybookResponse, + PlaybookUpdateRequest, + RepairStep, + SymptomPattern, + ) + + playbook_models = [ + Playbook, + PlaybookResponse, + PlaybookListResponse, + PlaybookCreateRequest, + PlaybookUpdateRequest, + PlaybookRecommendation, + SymptomPattern, + RepairStep, + ] + + for model in playbook_models: + schema = model.model_json_schema() + cleaned = extract_and_merge_defs(schema, all_definitions) + all_definitions[model.__name__] = cleaned + model_count += 1 + print(f" ✓ {model.__name__}") + + except ImportError as e: + print(f" ⚠ Import failed: {e}") + + print("\n📦 Other Models:") + # === CSRF Models === + try: + from models.csrf import CSRFTokenResponse + + schema = CSRFTokenResponse.model_json_schema() + cleaned = extract_and_merge_defs(schema, all_definitions) + all_definitions["CSRFTokenResponse"] = cleaned + model_count += 1 + print(" ✓ CSRFTokenResponse") + + except ImportError as e: + print(f" ⚠ CSRF import failed: {e}") + + # 修正所有 $ref 路徑 + all_definitions = fix_refs(all_definitions) + + # 組裝最終 schema + final_schema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "AWOOOI API Types", + "description": "Auto-generated from Pydantic models - DO NOT EDIT", + "definitions": all_definitions, + } + + # 寫入檔案 + output_file = OUTPUT_DIR / "api-types.json" + with open(output_file, "w", encoding="utf-8") as f: + json.dump(final_schema, f, indent=2, ensure_ascii=False) + + print(f"\n✅ Schema 生成完成: {output_file}") + print(f" 共 {len(all_definitions)} 個型別定義") + + return final_schema + + +if __name__ == "__main__": + print("🔄 開始生成 JSON Schema...\n") + generate_schemas()