mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 15:29:36 +00:00
Platform Services Layer (10 modules) — برج التحكم بالنمو - event_bus: 27 typed events (whatsapp/email/calendar/lead/payment/review/social/partner/sheet/crm/action) - identity_resolution: cross-channel merge (phone+email+CRM+social) with confidence scoring - channel_registry: 11 channels (WA, Gmail, Calendar, Moyasar, LinkedIn, X, IG, GBP, Sheets, CRM, Forms) with capabilities/risk/PDPL notes - action_policy: 9 rules (block_cold_whatsapp, block_payment_no_confirm, block_secrets, external_send_needs_approval, calendar_insert_needs_approval, social_dm_needs_explicit, unknown_source_review, high_value_deal_review, draft_only_safe) - tool_gateway: single execution chokepoint, env-flag-gated live actions (default OFF) - unified_inbox: 8 card types, ≤3 buttons enforced, Arabic - action_ledger: requested→approved→executed audit trail - proof_ledger: leads/meetings/drafts/sends/payments/revenue/risks_blocked/time_saved per channel - service_catalog: 12 sellable services - router api/routers/platform_services.py — 13 endpoints under /api/v1/platform/ Intelligence Layer (10 modules) — الشبكة العصبية للنمو - growth_brain: per-customer Brain + is_ready_for_autopilot() (≥30 signals + ≥40% accept) - command_feed: 9 daily card types (opportunity/revenue_leak/partner_suggestion/meeting_prep/review_response/competitive_move/customer_reactivation/ai_visibility_alert/action_required) - action_graph: 10 typed edges (signal→action→outcome) with what_works_summary - mission_engine: 7 missions, KILL FEATURE first_10_opportunities (10 فرص في 10 دقائق) - decision_memory: learns from accept/skip/edit/block, returns preferences (channels, tones, sectors, rejected actions, accept_rate) - trust_score: composite 0-100 (source+opt_in+channel+content+freq+approval) → safe/needs_review/blocked - revenue_dna: best_channel/segment/angle + common_objection + avg_cycle_days - opportunity_simulator: 9 Saudi sectors, expected_replies/meetings/deals/pipeline_sar + risk_score - competitive_moves: 8 move types with Arabic recommended_action_ar - board_brief: weekly Founder Shadow Board (3 decisions + 3 opportunities + 3 risks + relationship + experiment + metric) - router api/routers/intelligence_layer.py — 12 endpoints under /api/v1/intelligence/ Tests - tests/unit/test_platform_services.py — 31 tests covering catalog/channels/events/policy/gateway/identity/inbox/ledger/proof - tests/unit/test_intelligence_layer.py — 29 tests covering brain/feed/graph/missions/memory/trust/dna/simulator/competitive/brief - 60/60 new tests pass; full suite 587 passed, 2 skipped Docs - docs/PLATFORM_SERVICES_STRATEGY.md (Arabic) - docs/INTELLIGENCE_LAYER_STRATEGY.md (Arabic) - docs/DEALIX_100_PERCENT_LAUNCH_PLAN.md — added §32 Platform Services + §33 Intelligence Layer Safety - No live send by default (all WA/Gmail/Calendar/Moyasar guarded by env flags, all OFF) - All external actions go through Tool Gateway → Action Policy → draft/approval_required - No secrets allowed in payloads (block_secrets policy) - PDPL-aware: cold WhatsApp without consent is hard-blocked - Existing 477+ tests untouched (no breaking changes) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
174 lines
6.3 KiB
Python
174 lines
6.3 KiB
Python
"""
|
|
Action Policy Engine — decides whether an action can run, needs approval,
|
|
or is blocked. The single chokepoint that protects the customer's
|
|
reputation + enforces PDPL.
|
|
|
|
Design: pure deterministic rules. Easily testable, easily auditable,
|
|
easy for the customer to explain to compliance.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
|
|
# ── Policy rules — each rule is (action_type, condition, decision, reason_ar)
|
|
POLICY_RULES: list[dict[str, Any]] = [
|
|
# Hard blocks — never executed
|
|
{
|
|
"rule_id": "block_cold_whatsapp",
|
|
"action": "send_whatsapp",
|
|
"when": {"source": "cold_list", "consent": False},
|
|
"decision": "blocked",
|
|
"reason_ar": "WhatsApp البارد محظور بدون lawful basis (PDPL م.5).",
|
|
},
|
|
{
|
|
"rule_id": "block_payment_no_confirm",
|
|
"action": "charge_payment",
|
|
"when": {"user_confirmed": False},
|
|
"decision": "blocked",
|
|
"reason_ar": "الخصم يحتاج تأكيد المستخدم على Moyasar — لا charge مباشر.",
|
|
},
|
|
{
|
|
"rule_id": "block_secrets_in_payload",
|
|
"action": "*",
|
|
"when": {"payload_contains_secret": True},
|
|
"decision": "blocked",
|
|
"reason_ar": "تم اكتشاف secret في الـ payload — حماية تلقائية.",
|
|
},
|
|
# Approval gates — must pass through human
|
|
{
|
|
"rule_id": "external_send_needs_approval",
|
|
"action": "send_whatsapp,send_email,send_inmail,post_social",
|
|
"when": {"approval_status": "pending"},
|
|
"decision": "approval_required",
|
|
"reason_ar": "كل إرسال خارجي يحتاج موافقة العميل قبل التنفيذ.",
|
|
},
|
|
{
|
|
"rule_id": "calendar_insert_needs_approval",
|
|
"action": "calendar_insert_event",
|
|
"when": {"approval_status": "pending"},
|
|
"decision": "approval_required",
|
|
"reason_ar": "إنشاء اجتماع في تقويم العميل يحتاج موافقة قبل insert.",
|
|
},
|
|
{
|
|
"rule_id": "social_dm_needs_explicit",
|
|
"action": "send_social_dm",
|
|
"when": {"explicit_permission": False},
|
|
"decision": "approval_required",
|
|
"reason_ar": "DM السوشيال يحتاج إذن صريح لكل حساب.",
|
|
},
|
|
# Needs review
|
|
{
|
|
"rule_id": "unknown_source_review",
|
|
"action": "*",
|
|
"when": {"source": "unknown"},
|
|
"decision": "approval_required",
|
|
"reason_ar": "مصدر البيانات غير محدد — يحتاج توثيق lawful basis.",
|
|
},
|
|
{
|
|
"rule_id": "high_value_deal_review",
|
|
"action": "*",
|
|
"when": {"deal_value_sar_gte": 100_000},
|
|
"decision": "approval_required",
|
|
"reason_ar": "صفقة قيمتها ≥100K ريال — راجعها قبل التنفيذ.",
|
|
},
|
|
# Allowed (default for safe paths)
|
|
{
|
|
"rule_id": "draft_only_safe",
|
|
"action": "create_draft,read_data,classify_reply",
|
|
"when": {},
|
|
"decision": "allow",
|
|
"reason_ar": "إجراء داخلي آمن — لا يخرج للعميل النهائي.",
|
|
},
|
|
]
|
|
|
|
|
|
@dataclass
|
|
class PolicyDecision:
|
|
"""Output of evaluate_action."""
|
|
|
|
decision: str # allow / approval_required / blocked
|
|
matched_rule_id: str | None
|
|
reasons_ar: list[str] = field(default_factory=list)
|
|
suggested_next_action_ar: str = ""
|
|
|
|
|
|
def evaluate_action(
|
|
*,
|
|
action: str,
|
|
context: dict[str, Any] | None = None,
|
|
) -> PolicyDecision:
|
|
"""
|
|
Evaluate a proposed action against the policy rules.
|
|
|
|
First matching rule wins. Default: needs_review (defensive).
|
|
"""
|
|
ctx = context or {}
|
|
matched_reasons: list[str] = []
|
|
final_decision = "allow"
|
|
matched_rule_id: str | None = None
|
|
next_action = "ready_for_execution"
|
|
|
|
for rule in POLICY_RULES:
|
|
# Action match (comma-separated list, "*" = match-any)
|
|
applicable_actions = rule["action"].split(",") if rule["action"] != "*" else [action]
|
|
if action not in applicable_actions and rule["action"] != "*":
|
|
continue
|
|
|
|
# Condition match — every key in `when` must match the context
|
|
when = rule["when"]
|
|
cond_match = True
|
|
for k, expected in when.items():
|
|
if k.endswith("_gte"):
|
|
attr = k[:-4]
|
|
if not (float(ctx.get(attr, 0)) >= float(expected)):
|
|
cond_match = False
|
|
break
|
|
elif k == "payload_contains_secret":
|
|
if expected and not _has_secret_marker(ctx.get("payload", {})):
|
|
cond_match = False
|
|
break
|
|
elif ctx.get(k) != expected:
|
|
cond_match = False
|
|
break
|
|
|
|
if not cond_match:
|
|
continue
|
|
|
|
decision = rule["decision"]
|
|
matched_reasons.append(rule["reason_ar"])
|
|
matched_rule_id = rule["rule_id"]
|
|
|
|
if decision == "blocked":
|
|
return PolicyDecision(
|
|
decision="blocked",
|
|
matched_rule_id=matched_rule_id,
|
|
reasons_ar=matched_reasons,
|
|
suggested_next_action_ar="معالجة سبب الحظر قبل المحاولة مرة أخرى.",
|
|
)
|
|
if decision == "approval_required":
|
|
final_decision = "approval_required"
|
|
next_action = "operator_approves_then_execute"
|
|
# 'allow' rules just confirm — keep looking for stricter rule
|
|
|
|
return PolicyDecision(
|
|
decision=final_decision,
|
|
matched_rule_id=matched_rule_id,
|
|
reasons_ar=matched_reasons or ["لا قاعدة مطابقة — الإجراء آمن افتراضياً."],
|
|
suggested_next_action_ar=next_action,
|
|
)
|
|
|
|
|
|
# ── Helpers ──────────────────────────────────────────────────────
|
|
_SECRET_MARKERS = ("api_key", "secret_key", "private_key", "password", "ghp_", "sk-ant-", "moyasar_secret")
|
|
|
|
|
|
def _has_secret_marker(payload: dict[str, Any]) -> bool:
|
|
"""Cheap heuristic check — production pairs this with a stronger scanner."""
|
|
if not isinstance(payload, dict):
|
|
return False
|
|
flat = str(payload).lower()
|
|
return any(marker in flat for marker in _SECRET_MARKERS)
|