agentops-cockpit 0.5.0__py3-none-any.whl → 0.9.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. agent_ops_cockpit/agent.py +137 -0
  2. agent_ops_cockpit/cli/main.py +104 -11
  3. agent_ops_cockpit/eval/load_test.py +15 -10
  4. agent_ops_cockpit/eval/quality_climber.py +23 -5
  5. agent_ops_cockpit/eval/red_team.py +5 -4
  6. agent_ops_cockpit/mcp_server.py +55 -21
  7. agent_ops_cockpit/ops/arch_review.py +78 -17
  8. agent_ops_cockpit/ops/cost_optimizer.py +0 -1
  9. agent_ops_cockpit/ops/evidence_bridge.py +132 -0
  10. agent_ops_cockpit/ops/frameworks.py +79 -10
  11. agent_ops_cockpit/ops/mcp_hub.py +1 -2
  12. agent_ops_cockpit/ops/orchestrator.py +363 -49
  13. agent_ops_cockpit/ops/pii_scrubber.py +1 -1
  14. agent_ops_cockpit/ops/policies.json +26 -0
  15. agent_ops_cockpit/ops/policy_engine.py +85 -0
  16. agent_ops_cockpit/ops/reliability.py +30 -10
  17. agent_ops_cockpit/ops/secret_scanner.py +10 -3
  18. agent_ops_cockpit/ops/ui_auditor.py +52 -11
  19. agent_ops_cockpit/ops/watcher.py +138 -0
  20. agent_ops_cockpit/ops/watchlist.json +88 -0
  21. agent_ops_cockpit/optimizer.py +361 -53
  22. agent_ops_cockpit/shadow/router.py +7 -8
  23. agent_ops_cockpit/system_prompt.md +13 -0
  24. agent_ops_cockpit/tests/golden_set.json +52 -0
  25. agent_ops_cockpit/tests/test_agent.py +34 -0
  26. agent_ops_cockpit/tests/test_arch_review.py +45 -0
  27. agent_ops_cockpit/tests/test_frameworks.py +100 -0
  28. agent_ops_cockpit/tests/test_optimizer.py +68 -0
  29. agent_ops_cockpit/tests/test_quality_climber.py +18 -0
  30. agent_ops_cockpit/tests/test_red_team.py +35 -0
  31. agent_ops_cockpit/tests/test_secret_scanner.py +24 -0
  32. agentops_cockpit-0.9.5.dist-info/METADATA +246 -0
  33. agentops_cockpit-0.9.5.dist-info/RECORD +47 -0
  34. {agentops_cockpit-0.5.0.dist-info → agentops_cockpit-0.9.5.dist-info}/entry_points.txt +1 -1
  35. agentops_cockpit-0.5.0.dist-info/METADATA +0 -171
  36. agentops_cockpit-0.5.0.dist-info/RECORD +0 -32
  37. {agentops_cockpit-0.5.0.dist-info → agentops_cockpit-0.9.5.dist-info}/WHEEL +0 -0
  38. {agentops_cockpit-0.5.0.dist-info → agentops_cockpit-0.9.5.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,15 @@
1
1
  import typer
2
2
  import os
3
+ import re
3
4
  from rich.console import Console
4
5
  from rich.table import Table
5
6
  from rich.panel import Panel
6
7
 
8
+ from agent_ops_cockpit.ops.frameworks import detect_framework, FRAMEWORKS
9
+
7
10
  app = typer.Typer(help="Agent Architecture Reviewer: Audit your design against Google Well-Architected Framework.")
8
11
  console = Console()
9
12
 
10
- from agent_ops_cockpit.ops.frameworks import detect_framework, FRAMEWORKS
11
-
12
13
  @app.command()
13
14
  def audit(path: str = "."):
14
15
  """
@@ -18,15 +19,11 @@ def audit(path: str = "."):
18
19
  framework_data = FRAMEWORKS[framework_key]
19
20
  checklist = framework_data["checklist"]
20
21
  framework_name = framework_data["name"]
21
-
22
- console.print(Panel.fit(f"🏛️ [bold blue]{framework_name.upper()}: ARCHITECTURE REVIEW[/bold blue]", border_style="blue"))
23
- console.print(f"Detected Framework: [bold green]{framework_name}[/bold green]")
24
- console.print(f"Comparing local agent implementation against [bold]{framework_name} Best Practices[/bold]...\n")
25
-
26
22
  # Read all relevant code files for inspection
27
23
  code_content = ""
28
24
  for root, dirs, files in os.walk(path):
29
- if any(d in root for d in [".venv", "node_modules", ".git"]): continue
25
+ if any(d in root for d in [".venv", "node_modules", ".git"]):
26
+ continue
30
27
  for file in files:
31
28
  if file.endswith((".py", ".ts", ".tsx", ".js")):
32
29
  try:
@@ -35,8 +32,34 @@ def audit(path: str = "."):
35
32
  except Exception:
36
33
  pass
37
34
 
38
- total_checks = sum(len(section["checks"]) for section in checklist)
39
- passed_checks = 0
35
+ if framework_key == "generic":
36
+ console.print(Panel.fit("🔍 [bold yellow]SHADOW INTELLIGENCE: ZERO-SHOT AUDIT INITIALIZED[/bold yellow]", border_style="yellow"))
37
+ console.print("⚠️ [dim]Detected Unknown Technology Stack. Switching to Structural Pattern Matching...[/dim]")
38
+
39
+ # Self-Learning Heuristic: Look for patterns even if tech is unknown
40
+ structural_indicators = {
41
+ "decorators": r"@[\w\.]+",
42
+ "async_loops": r"async\s+def.*await",
43
+ "class_hierarchy": r"class\s+\w+\(\w*\):",
44
+ "environment_vars": r"os\.environ|process\.env",
45
+ "structured_output": r"Pydantic|BaseModel|zod|interface",
46
+ }
47
+
48
+ found_patterns = []
49
+ for p_name, pattern in structural_indicators.items():
50
+ if re.search(pattern, code_content):
51
+ found_patterns.append(p_name)
52
+
53
+ if found_patterns:
54
+ console.print(f"📡 [bold green]Heuristically identified patterns:[/bold green] {', '.join(found_patterns)}")
55
+ console.print("Adjusting audit benchmarks for custom agentic architecture...\n")
56
+
57
+ console.print(Panel.fit(f"🏛️ [bold blue]{framework_name.upper()}: ARCHITECTURE REVIEW[/bold blue]", border_style="blue"))
58
+ console.print(f"Detected Framework: [bold green]{framework_name}[/bold green]")
59
+ console.print(f"Comparing local agent implementation against [bold]{framework_name} Best Practices[/bold]...\n")
60
+
61
+ total_checks = 0.0
62
+ passed_checks = 0.0
40
63
  current_check_num = 0
41
64
 
42
65
  with console.status("[bold blue]Scanning architecture...") as status:
@@ -49,7 +72,7 @@ def audit(path: str = "."):
49
72
  for check_text, rationale in section["checks"]:
50
73
  current_check_num += 1
51
74
  check_key = check_text.split(":")[0].strip()
52
- status.update(f"[bold blue][{current_check_num}/{total_checks}] Checking {check_key}...")
75
+ status.update(f"[bold blue]Step {current_check_num}: Checking {check_key}...")
53
76
 
54
77
  # Simple heuristic audit: check if certain keywords exist in the code
55
78
  keywords = {
@@ -59,7 +82,7 @@ def audit(path: str = "."):
59
82
  "Identity": ["iam", "auth", "token", "oauth", "workloadidentity"],
60
83
  "Moderation": ["moderate", "safety", "filter"],
61
84
  "Routing": ["router", "switch", "map", "agentengine"],
62
- "Outputs": ["schema", "json", "structured"],
85
+ "Outputs": ["schema", "json", "structured", "basemodel", "interface"],
63
86
  "HITL": ["approve", "confirm", "human"],
64
87
  "Confirmation": ["confirm", "ask", "approve"],
65
88
  "Logging": ["log", "trace", "audit", "reasoningengine"],
@@ -69,9 +92,39 @@ def audit(path: str = "."):
69
92
  "A2UI": ["a2ui", "renderer", "registry", "component"],
70
93
  "Responsive": ["@media", "max-width", "flex", "grid", "vw", "vh"],
71
94
  "Accessibility": ["aria-", "role=", "alt=", "tabindex"],
72
- "Triggers": ["trigger", "callback", "handle", "onclick"]
95
+ "Policies": ["policies.json", "policy_engine", "forbidden_topics", "hitl"],
96
+ "Triggers": ["trigger", "callback", "handle", "onclick"],
97
+ "Resiliency": ["retry", "tenacity", "backoff", "exponential"],
98
+ "Prompts": [".md", ".yaml", ".prompt", "load_prompt", "jinja2"],
99
+ "Sessions": ["session", "state", "conversation_id", "thread_id"],
100
+ "Retrieval": ["rag", "vector", "embedding", "context_cache", "retrieval", "pinecone", "alloydb", "cloudsql", "bigquery", "firestore", "spanner", "redshift", "snowflake", "databricks", "s3", "blob"],
101
+ "Reasoning": ["while", "for", "loop", "invoke", "call", "run", "execute", "chain", "agent"],
102
+ "State": ["memory", "state", "db", "redis", "history", "session", "storage"],
103
+ "Tools": ["tool", "registry", "dispatcher", "handler", "mcp", "api", "sdk", "client", "connect"],
104
+ "Safety": ["filter", "clean", "sanitize", "scrub", "guard"],
105
+ "Shadow Mode": ["shadow", "router", "dual_rollout", "traffic_split", "version_v2"],
106
+ "Orchestration": ["swarm", "coordinator", "manager_agent", "supervisor", "orchestrator", "worker_agent"],
107
+ "VPC": ["vpc_sc", "service_control", "isolated_network", "private_endpoint"],
108
+ "Observability": ["otel", "trace", "span", "telemetry", "opentelemetry", "cloud_trace"],
109
+ "Governance": ["policies.json", "hitl", "approval", "policy_engine"],
110
+ "Legal": ["copyright", "license", "disclaimer", "data_residency", "privacy", "tos", "terms_of_service"],
111
+ "Marketing": ["brand", "tone", "vibrant", "consistent", "seo", "og:image", "description", "cta"]
112
+ }
113
+
114
+ # Weighting: Security and Core Architecture are more important
115
+ weights = {
116
+ "🏗️": 1.5,
117
+ "🛡️": 2.0,
118
+ "🎭": 1.0,
119
+ "🧗": 1.2,
120
+ "📉": 1.3,
121
+ "⚖️": 1.8, # Legal/Compliance
122
+ "📢": 0.9 # Marketing/Brand
73
123
  }
74
124
 
125
+ category_prefix = section["category"][:2]
126
+ weight = weights.get(category_prefix, 1.0)
127
+
75
128
  # If any keyword for this check type is found, mark as PASSED
76
129
  matched = False
77
130
  for k, words in keywords.items():
@@ -82,12 +135,18 @@ def audit(path: str = "."):
82
135
 
83
136
  if matched:
84
137
  check_status = "[bold green]PASSED[/bold green]"
85
- passed_checks += 1
138
+ passed_checks += weight
139
+ # Output source for evidence bridge
140
+ if "Google" in framework_name:
141
+ console.print(f"SOURCE: {check_key} | https://cloud.google.com/architecture/framework | Google Cloud Architecture Framework: {section['category']}")
86
142
  else:
87
143
  check_status = "[bold red]FAIL[/bold red]"
144
+ # Output action for report
145
+ console.print(f"ACTION: codebase | Architecture Gap: {check_key} | {rationale}")
146
+ if "Google" in framework_name:
147
+ console.print(f"SOURCE: {check_key} | https://cloud.google.com/architecture/framework | Recommended Pattern: {check_text}")
88
148
 
89
- import time
90
- time.sleep(0.1) # Simulate deep heuristic scan
149
+ total_checks += weight
91
150
 
92
151
  table.add_row(check_text, check_status, rationale)
93
152
 
@@ -97,8 +156,10 @@ def audit(path: str = "."):
97
156
  score = (passed_checks / total_checks) * 100 if total_checks > 0 else 0
98
157
  console.print(f"📊 [bold]Review Score: {score:.0f}/100[/bold]")
99
158
  if score >= 80:
100
- console.print(f"✅ [bold green]Architecture Review Complete.[/bold green] Your agent is well-aligned with {framework_name} patterns.")
159
+ console.print("✅ [bold green]Architecture Review Complete.[/bold green] Your agent is well-aligned with optimized patterns.")
101
160
  else:
161
+ if framework_key == "generic":
162
+ console.print("💡 [bold yellow]Self-Learning Note:[/bold yellow] Found unknown tech. I have mapped your code structure to universal agentic pillars (Reasoning/Tools/Safety).")
102
163
  console.print("⚠️ [bold yellow]Review Complete with warnings.[/bold yellow] Your agent has gaps in best practices. See results above.")
103
164
 
104
165
  if __name__ == "__main__":
@@ -1,4 +1,3 @@
1
- from typing import Dict
2
1
  import time
3
2
 
4
3
  class CostOptimizer:
@@ -0,0 +1,132 @@
1
+ import json
2
+ import os
3
+ import urllib.request
4
+ import xml.etree.ElementTree as ET
5
+ import re
6
+ from typing import Dict, Any, Optional, List
7
+ import importlib.metadata
8
+ from packaging import version
9
+ from rich.console import Console
10
+
11
+ console = Console()
12
+
13
+ WATCHLIST_PATH = os.path.join(os.path.dirname(__file__), "watchlist.json")
14
+
15
+ def clean_version(v_str: str) -> str:
16
+ match = re.search(r'(\d+\.\d+(?:\.\d+)?(?:[a-zA-Z]+\d+)?)', v_str)
17
+ if match:
18
+ return match.group(1)
19
+ return v_str.strip().lstrip('v')
20
+
21
+ def fetch_latest_from_atom(url: str) -> Optional[Dict[str, str]]:
22
+ try:
23
+ req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
24
+ with urllib.request.urlopen(req, timeout=10) as response:
25
+ tree = ET.parse(response)
26
+ root = tree.getroot()
27
+ ns = {'ns': 'http://www.w3.org/2005/Atom'}
28
+
29
+ latest_entry = root.find('ns:entry', ns)
30
+ if latest_entry is not None:
31
+ title = latest_entry.find('ns:title', ns).text
32
+ updated = latest_entry.find('ns:updated', ns).text
33
+ content_node = latest_entry.find('ns:content', ns)
34
+ summary = ""
35
+ if content_node is not None:
36
+ summary = re.sub('<[^<]+?>', '', content_node.text or "")[:500] + "..."
37
+
38
+ raw_v = title.strip().split()[-1]
39
+ return {
40
+ "version": clean_version(raw_v) if "==" not in raw_v else clean_version(raw_v.split("==")[-1]),
41
+ "date": updated,
42
+ "title": title,
43
+ "summary": summary
44
+ }
45
+ except Exception:
46
+ return None
47
+ return None
48
+
49
+ def get_installed_version(package_name: str) -> str:
50
+ try:
51
+ return importlib.metadata.version(package_name)
52
+ except importlib.metadata.PackageNotFoundError:
53
+ return "Not Installed"
54
+
55
+ def get_package_evidence(package_name: str) -> Dict[str, Any]:
56
+ if not os.path.exists(WATCHLIST_PATH):
57
+ return {"error": "Watchlist not found"}
58
+
59
+ with open(WATCHLIST_PATH, 'r') as f:
60
+ watchlist = json.load(f)
61
+
62
+ # Flatten categories to find the package
63
+ for cat_name, cat in watchlist.items():
64
+ if cat_name == "compatibility_rules":
65
+ continue
66
+ for name, info in cat.items():
67
+ if info.get("package") == package_name or name == package_name:
68
+ latest = fetch_latest_from_atom(info["feed"])
69
+ installed = get_installed_version(package_name)
70
+ min_v = info.get("min_version_for_optimizations", "0.0.0")
71
+
72
+ upgrade_required = False
73
+ if installed != "Not Installed":
74
+ try:
75
+ if version.parse(installed) < version.parse(min_v):
76
+ upgrade_required = True
77
+ except Exception:
78
+ pass
79
+
80
+ return {
81
+ "package": package_name,
82
+ "installed_version": installed,
83
+ "latest_version": latest["version"] if latest else "Unknown",
84
+ "min_optimized_version": min_v,
85
+ "upgrade_required": upgrade_required,
86
+ "release_date": latest["date"] if latest else "Unknown",
87
+ "source_url": info["feed"].replace(".atom", ""),
88
+ "best_practice_context": latest["summary"] if latest else "Check release notes for performance/security enhancements."
89
+ }
90
+ return {"error": f"Package {package_name} not found in watchlist"}
91
+
92
+ def get_compatibility_report(installed_packages: List[str]) -> List[Dict[str, Any]]:
93
+ if not os.path.exists(WATCHLIST_PATH):
94
+ return []
95
+
96
+ with open(WATCHLIST_PATH, 'r') as f:
97
+ watchlist = json.load(f)
98
+
99
+ rules = watchlist.get("compatibility_rules", [])
100
+ reports = []
101
+
102
+ # Normalize imports to find root package names
103
+ roots = set()
104
+ for pkg in installed_packages:
105
+ roots.add(pkg.split('.')[0].replace('-', '_'))
106
+
107
+ for rule in rules:
108
+ comp_root = rule["component"].replace('-', '_')
109
+ if comp_root in roots:
110
+ # Check for incompatibilities
111
+ for forbidden in rule.get("incompatible_with", []):
112
+ forbidden_root = forbidden.replace('-', '_')
113
+ if forbidden_root in roots:
114
+ reports.append({
115
+ "type": "INCOMPATIBLE",
116
+ "component": rule["component"],
117
+ "conflict_with": forbidden,
118
+ "reason": rule["reason"]
119
+ })
120
+
121
+ # Check for synergies
122
+ for synergy in rule.get("works_well_with", []):
123
+ synergy_root = synergy.replace('-', '_')
124
+ if synergy_root in roots:
125
+ reports.append({
126
+ "type": "SYNERGY",
127
+ "component": rule["component"],
128
+ "partner": synergy,
129
+ "reason": f"Optimally paired with ecosystem partner {synergy}."
130
+ })
131
+
132
+ return reports
@@ -1,6 +1,5 @@
1
1
  import os
2
2
  import re
3
- from typing import Dict, List, Any
4
3
 
5
4
  # --- CHECKLISTS ---
6
5
 
@@ -11,7 +10,8 @@ GOOGLE_CHECKLIST = [
11
10
  ("Runtime: Is the agent running on Cloud Run or GKE?", "Critical for scalability and cost."),
12
11
  ("Framework: Is ADK used for tool orchestration?", "Google-standard for agent-tool communication."),
13
12
  ("Sandbox: Is Code Execution running in Vertex AI Sandbox?", "Prevents malicious code execution."),
14
- ("Backend: Is FastAPI used for the Engine layer?", "Industry-standard for high-concurrency agent apps.")
13
+ ("Backend: Is FastAPI used for the Engine layer?", "Industry-standard for high-concurrency agent apps."),
14
+ ("Outputs: Are Pydantic or Response Schemas used for structured output?", "Ensures data integrity and reliable tool execution.")
15
15
  ]
16
16
  },
17
17
  {
@@ -19,7 +19,8 @@ GOOGLE_CHECKLIST = [
19
19
  "checks": [
20
20
  ("PII: Is a scrubber active before sending data to LLM?", "Compliance requirement (GDPR/SOC2)."),
21
21
  ("Identity: Is IAM used for tool access?", "Ensures least-privilege security."),
22
- ("Safety: Are Vertex AI Safety Filters configured?", "Protects against toxic generation.")
22
+ ("Safety: Are Vertex AI Safety Filters configured?", "Protects against toxic generation."),
23
+ ("Policies: Is 'policies.json' used for declarative guardrails?", "Enforces RFC-307 standards for forbidden topics and tool HITL.")
23
24
  ]
24
25
  },
25
26
  {
@@ -47,6 +48,33 @@ GOOGLE_CHECKLIST = [
47
48
  ("Accessibility: Do interactive elements have aria-labels?", "Critical for inclusive design and automated testing."),
48
49
  ("Triggers: Are you using interactive triggers for state changes?", "Improves 'Agentic Feel' through reactive UI.")
49
50
  ]
51
+ },
52
+ {
53
+ "category": "🧗 Resiliency & Best Practices",
54
+ "checks": [
55
+ ("Resiliency: Are retries with exponential backoff used for API/DB calls?", "Prevents cascading failures during downtime (e.g., using tenacity)."),
56
+ ("Prompts: Are prompts stored in external '.md' or '.yaml' files?", "Best practice for separation of concerns and versioning."),
57
+ ("Sessions: Is there a session/conversation management layer?", "Ensures context continuity and user state tracking."),
58
+ ("Retrieval: Are you using RAG or Efficient Context Caching for large datasets?", "Optimizes performance vs. cost for retrieval-heavy agents.")
59
+ ]
60
+ },
61
+ {
62
+ "category": "⚖️ Legal & Compliance",
63
+ "checks": [
64
+ ("Copyright: Does every source file have a legal copyright header?", "IP protection and enterprise policy."),
65
+ ("License: Is there a LICENSE file in the root?", "Mandatory for legal distribution."),
66
+ ("Disclaimer: Does the agent provide a clear LLM-usage disclaimer?", "Liability mitigation for AI hallucinations."),
67
+ ("Data Residency: Is the agent region-restricted to us-central1 or equivalent?", "Ensures data stays within geofenced boundaries.")
68
+ ]
69
+ },
70
+ {
71
+ "category": "📢 Marketing & Brand",
72
+ "checks": [
73
+ ("Tone: Is the system prompt aligned with brand voice (Helpful/Professional)?", "Consistency in agent personality."),
74
+ ("SEO: Are OpenGraph and meta-tags present in the Face layer?", "Critical for discoverability and social sharing."),
75
+ ("Vibrancy: Does the UI use the standard corporate color palette?", "Prevents ad-hoc branding in autonomous UIs."),
76
+ ("CTA: Is there a clear Call-to-Action for every agent proposing a tool?", "Drives conversion and user engagement.")
77
+ ]
50
78
  }
51
79
  ]
52
80
 
@@ -214,18 +242,49 @@ LANGCHAIN_CHECKLIST = [
214
242
 
215
243
  GENERIC_CHECKLIST = [
216
244
  {
217
- "category": "🏗️ General Agent Architecture",
245
+ "category": "🏗️ Zero-Shot Discovery (Unknown Tech)",
246
+ "checks": [
247
+ ("Reasoning: Does the code exhibit a core reasoning/execution loop?", "Detected Structural Pattern: Universal Agentic Loop."),
248
+ ("State: Is there an identifiable state management or memory pattern?", "Ensures session continuity even in custom stacks."),
249
+ ("Tools: Are external functions being called via a registry or dispatcher?", "Standard for tool-enabled agents."),
250
+ ("Safety: Are there any input/output sanitization blocks?", "Basic security hygiene for any AI application.")
251
+ ]
252
+ }
253
+ ]
254
+
255
+ ORACLE_CHECKLIST = [
256
+ {
257
+ "category": "🏗️ Oracle Cloud Architecture",
218
258
  "checks": [
219
- ("Tooling: Does the agent use structured tool calling?", "Essential for reliable interactions."),
220
- ("Orchestration: Is there a clear reason-act loop?", "Ensures agentic behavior."),
221
- ("Observability: Are traces/logs being captured?", "Critical for debugging production agents.")
259
+ ("Platform: Using OCI Generative AI or AI Agents?", "OCI-native managed agent orchestration."),
260
+ ("Data: Is Oracle Database 23ai (Vector Search) used?", "Enterprise-grade vector grounding for RAG."),
261
+ ("Compute: Is the agent running on OCI Container Instances or OCI Functions?", "Scale-to-zero and high-performance OCI compute options.")
222
262
  ]
223
263
  },
224
264
  {
225
- "category": "🛡️ Security",
265
+ "category": "🛡️ Security & Governance (Oracle)",
226
266
  "checks": [
227
- ("Sandbox: Are tools running in an isolated environment?", "Protects the host system."),
228
- ("Input Validation: Are tool arguments validated?", "Prevents local execution attacks.")
267
+ ("Identity: Is OCI IAM with dynamic groups enabled?", "Ensures secure, credential-less access to OCI resources."),
268
+ ("Secrets: Using OCI Vault for API/DB secrets?", "Production standard for key management on OCI."),
269
+ ("Network: Is the agent isolated in an OCI VCN with Private Endpoints?", "Prevents internet exposure of internal agent tools.")
270
+ ]
271
+ }
272
+ ]
273
+
274
+ CREWAI_CHECKLIST = [
275
+ {
276
+ "category": "🏗️ CrewAI Multi-Agent Architecture",
277
+ "checks": [
278
+ ("Orchestration: Is the 'Process' defined (Sequential/Hierarchical)?", "CrewAI best practice for complex team coordination."),
279
+ ("Memory: Is Short-term or Long-term memory enabled?", "Critical for maintaining context across multi-agent tasks."),
280
+ ("Tools: Are tools shared across the Crew or specific to Agents?", "Promotes agent specialization and efficiency.")
281
+ ]
282
+ },
283
+ {
284
+ "category": "🛡️ Security & Reliability",
285
+ "checks": [
286
+ ("Manager: Is a 'Manager Agent' used for hierarchical crews?", "Provides a central governance layer for agent handoffs."),
287
+ ("Delegation: Is 'allow_delegation' configured per agent?", "Controls the communication flow between autonomous agents.")
229
288
  ]
230
289
  }
231
290
  ]
@@ -370,6 +429,16 @@ FRAMEWORKS = {
370
429
  "checklist": FIREBASE_CHECKLIST,
371
430
  "indicators": [r"firebase\.json", r"\.firebaserc", r"firestore"]
372
431
  },
432
+ "oracle": {
433
+ "name": "Oracle Cloud Infrastructure (OCI)",
434
+ "checklist": ORACLE_CHECKLIST,
435
+ "indicators": [r"oci", r"oracle", r"23ai"]
436
+ },
437
+ "crewai": {
438
+ "name": "CrewAI",
439
+ "checklist": CREWAI_CHECKLIST,
440
+ "indicators": [r"crewai", r"Agent\(", r"Task\(", r"Crew\("]
441
+ },
373
442
  "generic": {
374
443
 
375
444
  "name": "Generic Agentic Stack",
@@ -1,6 +1,5 @@
1
- from typing import List, Dict, Any, Optional
1
+ from typing import List, Dict, Any
2
2
  import asyncio
3
- import json
4
3
  import os
5
4
  from mcp import ClientSession, StdioServerParameters
6
5
  from mcp.client.stdio import stdio_client