Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions lib/crewai/src/crewai/utilities/primordia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""Primordia metering for CrewAI agents."""
import hashlib
import json
import time
from typing import Dict, List, Optional


class PrimordiaMeter:
"""Meter that emits MSR receipts for crew task execution.

Shadow mode by default - no network calls, no blocking.

Example:
>>> from crewai.utilities import PrimordiaMeter
>>> meter = PrimordiaMeter(agent_id="crew-alpha")
>>> crew = Crew(agents=[...], tasks=[...], meter=meter)
"""

def __init__(
self,
agent_id: str,
kernel_url: str = "https://clearing.kaledge.app",
):
self.agent_id = agent_id
self.kernel_url = kernel_url
self.receipts: List[Dict] = []

def record_task(
self,
task_name: str,
agent_name: str,
tokens_used: int,
model: str = "unknown",
metadata: Optional[Dict] = None,
) -> str:
"""Record a task execution as MSR receipt."""
unit_price = 80 # default
if "gpt-4" in model.lower():
unit_price = 300
elif "claude" in model.lower():
unit_price = 100

receipt = {
"meter_version": "0.1",
"type": "compute",
"agent_id": self.agent_id,
"provider": model,
"units": tokens_used,
"unit_price_usd_micros": unit_price,
"total_usd_micros": tokens_used * unit_price,
"timestamp_ms": int(time.time() * 1000),
"metadata": {
"framework": "crewai",
"task": task_name,
"agent": agent_name,
**(metadata or {})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User metadata can silently override critical receipt fields

The metadata dict is unpacked after framework, task, and agent are set, meaning user-provided metadata containing these keys will silently override the values from the explicit task_name and agent_name parameters. For receipts used in billing/settlement, this could lead to incorrect data. If a user accidentally reuses a dict that contains a task or agent key, the receipt would have wrong identifiers despite passing correct explicit parameters.

Fix in Cursor Fix in Web

}

receipt_hash = hashlib.sha256(
json.dumps(receipt, sort_keys=True).encode()
).hexdigest()[:32]

self.receipts.append({"hash": receipt_hash, "receipt": receipt})
return receipt_hash

def get_crew_cost(self) -> float:
"""Get total crew cost in USD."""
return sum(r["receipt"]["total_usd_micros"] for r in self.receipts) / 1_000_000

def get_receipts(self) -> List[Dict]:
"""Get all receipts for settlement."""
return self.receipts