## Phase 1-3: Control Plane + Contract System - awooop_phase1_control_plane_2026-05-04.sql: 12 張核心表 + RLS - awooop_phase1_batch1_rls_2026-05-04.sql: 全部 FORCE RLS + GRANT - packages/awooop-contracts/: 六合約 JSON Schema + golden fixtures - src/models/awooop_contracts.py: Pydantic v2 contract models(extra=forbid) - src/repositories/contract_repository.py: contract lifecycle(draft→published→active) - src/services/contract_service.py: HMAC publish sig + Redis multi-sig activate - src/services/schema_validator.py: LLM output validator(retry×3, E-SCHEMA-001) ## Phase 2: Tenant Isolation - awooop_phase2_budget_ledger_2026-05-04.sql: budget_ledger + RLS - src/services/budget_service.py: Token Budget Hard Kill 三層防線 - src/core/context.py: PROJECT_ID ContextVar(31 background loop 自動繼承) - src/db/base.py + models.py: project_id 欄位 + RLS set_config 注入 - src/hermes/nl_gateway.py: project_id Redis key 前綴(Phase A 雙寫) - src/services/anomaly_counter.py: per-project 改造(Phase A fallback) ## Phase 4: Platform Shell in Shadow Mode - awooop_phase4_run_state_2026-05-04.sql: run_state + step_journal + idempotency - src/services/run_state_machine.py: 8-state FSM + SKIP LOCKED + stale reaper - src/services/platform_runtime.py: UUID v7 + W3C trace_id + shadow_execute - src/services/audit_sink.py: PII/secret redaction 9 patterns - src/api/v1/platform/runs.py: POST/GET /v1/platform/runs(Router→Service 架構) - src/workers/platform_worker.py: SKIP LOCKED worker + heartbeat + reaper loop - src/main.py: platform router + lifespan worker start/stop ## Phase 5: MCP Gateway 五閘門 - awooop_phase5_mcp_gateway_2026-05-04.sql: 4 表 + RLS - src/plugins/mcp/gateway.py: McpGateway(Gate 1~5, E-MCP-GATE-001~009) - src/plugins/mcp/redaction_middleware.py: 雙層 redaction + 16K 截斷 - src/plugins/mcp/registry.py: __provider name mangling(ADR-116) - src/plugins/mcp/credential_resolver.py: k8s secret ref 解析 - tests/test_mcp_credential_isolation.py: 10 個迴歸測試(secret leak 防再現) ## Phase 6-8: EwoooC + Channel Hub + Approval Token - awooop_phase6_ewoooc_onboarding_2026-05-04.sql: ewoooc tenant + 4 read-only MCP tools - awooop_phase7_channel_hub_2026-05-04.sql: conversation_event + outbound_message - src/services/provider_proxy.py: ProviderProxy + PlatformEnvelope(ADR-115) - src/services/channel_hub.py: Telegram inbound mirror + Progressive Feedback(30s) - src/services/awooop_approval_token.py: HS256 + jti NX replay 防護 + suggest mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
118 lines
3.6 KiB
JSON
118 lines
3.6 KiB
JSON
{
|
||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||
"$id": "https://awooop.platform/contracts/v1/policy_routing",
|
||
"title": "Policy Routing Contract",
|
||
"description": "AwoooP 路由/政策合約 — 定義 LLM 路由規則、fallback 順序與費用保護",
|
||
"type": "object",
|
||
"required": ["policy_id", "policy_name", "routing_rules"],
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"policy_id": {
|
||
"type": "string",
|
||
"pattern": "^[a-z0-9][a-z0-9_-]{1,127}$",
|
||
"description": "Policy 識別符"
|
||
},
|
||
"policy_name": {
|
||
"type": "string",
|
||
"minLength": 1,
|
||
"maxLength": 256,
|
||
"description": "人類可讀政策名稱"
|
||
},
|
||
"routing_rules": {
|
||
"type": "array",
|
||
"minItems": 1,
|
||
"items": {
|
||
"type": "object",
|
||
"required": ["rule_id", "priority", "provider", "model"],
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"rule_id": {"type": "string"},
|
||
"priority": {
|
||
"type": "integer",
|
||
"minimum": 0,
|
||
"maximum": 9999,
|
||
"description": "數字越小優先級越高"
|
||
},
|
||
"provider": {
|
||
"type": "string",
|
||
"enum": ["anthropic", "openai", "ollama", "gemini", "nvidia", "openrouter"]
|
||
},
|
||
"model": {"type": "string"},
|
||
"condition": {
|
||
"type": "object",
|
||
"description": "路由條件(task_type, token_budget, time_range 等)",
|
||
"properties": {
|
||
"task_types": {
|
||
"type": "array",
|
||
"items": {"type": "string"}
|
||
},
|
||
"max_prompt_tokens": {"type": "integer", "minimum": 1},
|
||
"time_range": {
|
||
"type": "object",
|
||
"properties": {
|
||
"start_utc": {"type": "string", "pattern": "^[0-2][0-9]:[0-5][0-9]$"},
|
||
"end_utc": {"type": "string", "pattern": "^[0-2][0-9]:[0-5][0-9]$"}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
"weight": {
|
||
"type": "integer",
|
||
"minimum": 1,
|
||
"maximum": 100,
|
||
"default": 100,
|
||
"description": "同 priority 時的加權比例(用於 A/B 流量分割)"
|
||
}
|
||
}
|
||
},
|
||
"description": "路由規則清單(按 priority 升序評估)"
|
||
},
|
||
"fallback_provider": {
|
||
"type": "string",
|
||
"enum": ["anthropic", "openai", "ollama", "gemini", "nvidia", "openrouter"],
|
||
"description": "所有規則 miss 時的最終 fallback"
|
||
},
|
||
"fallback_model": {
|
||
"type": "string",
|
||
"description": "fallback_provider 使用的模型"
|
||
},
|
||
"max_cost_per_run_usd": {
|
||
"type": ["number", "null"],
|
||
"minimum": 0,
|
||
"description": "單次 run 費用上限;null = 無限制"
|
||
},
|
||
"retry_policy": {
|
||
"type": "object",
|
||
"additionalProperties": false,
|
||
"properties": {
|
||
"max_retries": {
|
||
"type": "integer",
|
||
"minimum": 0,
|
||
"maximum": 10,
|
||
"default": 3
|
||
},
|
||
"backoff_base_seconds": {
|
||
"type": "number",
|
||
"minimum": 0.1,
|
||
"maximum": 60,
|
||
"default": 1.0
|
||
},
|
||
"retry_on_provider_errors": {
|
||
"type": "boolean",
|
||
"default": true
|
||
}
|
||
}
|
||
},
|
||
"effective_from": {
|
||
"type": "string",
|
||
"format": "date-time",
|
||
"description": "政策生效起始時間(ISO 8601)"
|
||
},
|
||
"effective_to": {
|
||
"type": ["string", "null"],
|
||
"format": "date-time",
|
||
"description": "政策生效結束時間;null = 永久有效"
|
||
}
|
||
}
|
||
}
|