{"version":3,"file":"autonomy-profiles.mjs","names":[],"sources":["../../../src/services/autonomy-profiles.ts"],"sourcesContent":["/**\n * Graduated Autonomy Profiles\n *\n * Preset delegation configurations that give users easy on-ramps to\n * agent autonomy. Each profile defines a set of policy rules and\n * recommended delegation parameters.\n *\n * Profiles:\n *   supervised    — no delegation, all actions require ClawnchConnect approval\n *   training      — small limits, short expiry, limited actions\n *   autonomous    — production-level limits, weekly budgets, approved contracts\n *   custom        — user-defined (just a label, no preset rules)\n *\n * The /profile command creates policies from a profile template, then\n * optionally compiles them to on-chain delegations in delegation mode.\n */\n\nimport type {\n  Policy,\n  PolicyRule,\n  PolicyScope,\n} from './policy-types.js';\nimport { getPolicyMode, isDelegationMode } from './policy-types.js';\nimport { getPolicyStore } from './policy-store.js';\nimport { randomUUID } from 'node:crypto';\n\n// ─── Profile Types ──────────────────────────────────────────────────────\n\nexport type ProfileId = 'supervised' | 'training' | 'autonomous' | 'custom';\n\nexport interface AutonomyProfile {\n  id: ProfileId;\n  name: string;\n  description: string;\n  /** Human-readable summary of what the agent can do. */\n  summary: string[];\n  /** Policy rules created when profile is activated. */\n  rules: PolicyRule[];\n  /** Which tool categories are in scope. Empty = all tools. */\n  scopeCategories: string[];\n  /** Delegation parameters (for on-chain mode). */\n  delegation: {\n    /** Expiry duration in seconds. 0 = no delegation (supervised). */\n    expirySec: number;\n    /** Max single-tx value in USD. 0 = no cap (uses spending limit). */\n    maxTxUsd: number;\n  };\n}\n\n// ─── Profile Definitions ────────────────────────────────────────────────\n\nconst PROFILES: Record<ProfileId, AutonomyProfile> = {\n  supervised: {\n    id: 'supervised',\n    name: 'Supervised',\n    description: 'All actions require wallet approval via ClawnchConnect.',\n    summary: [\n      'Every transaction goes to your wallet for manual approval.',\n      'No spending limits — you review each action.',\n      'No on-chain delegation created.',\n      'This is the safest mode. The agent cannot act without you.',\n    ],\n    rules: [],\n    scopeCategories: [],\n    delegation: { expirySec: 0, maxTxUsd: 0 },\n  },\n\n  training: {\n    id: 'training',\n    name: 'Training Wheels',\n    description: 'Small limits, short expiry. Good for getting started.',\n    summary: [\n      'Max $50 per transaction.',\n      'Max $200/day total spending.',\n      'Max 10 write actions per day.',\n      '24-hour expiry — delegation auto-expires.',\n      'Only DeFi and transfer tools allowed.',\n    ],\n    rules: [\n      { type: 'max_amount', maxAmountUsd: 50 },\n      { type: 'spending_limit', maxAmountUsd: 200, period: 'daily' },\n      { type: 'rate_limit', maxCalls: 10, periodMs: 86_400_000 },\n    ],\n    scopeCategories: ['defi', 'transfer'],\n    delegation: { expirySec: 86_400, maxTxUsd: 50 },\n  },\n\n  autonomous: {\n    id: 'autonomous',\n    name: 'Autonomous',\n    description: 'Production-level autonomy with weekly budgets.',\n    summary: [\n      'Max $500 per transaction.',\n      'Max $2,000/week total spending.',\n      'Max 50 write actions per day.',\n      '30-day expiry — renew monthly.',\n      'DeFi, transfers, and orchestration tools allowed.',\n      'Confirmation required above $500.',\n    ],\n    rules: [\n      { type: 'max_amount', maxAmountUsd: 500 },\n      { type: 'spending_limit', maxAmountUsd: 2000, period: 'weekly' },\n      { type: 'rate_limit', maxCalls: 50, periodMs: 86_400_000 },\n      { type: 'approval_threshold', amountUsd: 500 },\n    ],\n    scopeCategories: ['defi', 'transfer', 'orchestration'],\n    delegation: { expirySec: 2_592_000, maxTxUsd: 500 },\n  },\n\n  custom: {\n    id: 'custom',\n    name: 'Custom',\n    description: 'Define your own rules using natural language policies.',\n    summary: [\n      'No preset rules — you define everything.',\n      'Use `/policies` to create and manage rules.',\n      'Use `/delegate create <name>` to compile to on-chain delegation.',\n    ],\n    rules: [],\n    scopeCategories: [],\n    delegation: { expirySec: 0, maxTxUsd: 0 },\n  },\n};\n\n// ─── Profile Store ──────────────────────────────────────────────────────\n\n/** Prefix for policies created by profile activation. */\nconst PROFILE_POLICY_PREFIX = 'profile:';\n\n/** In-memory cache of active profile per user. */\nconst _activeProfiles = new Map<string, ProfileId>();\n\n/** Get the list of all available profiles. */\nexport function listProfiles(): AutonomyProfile[] {\n  return Object.values(PROFILES);\n}\n\n/** Get a profile by ID. */\nexport function getProfile(id: string): AutonomyProfile | undefined {\n  return PROFILES[id as ProfileId];\n}\n\n/** Get the active profile for a user (checks existing policies). */\nexport function getActiveProfile(userId: string): ProfileId {\n  // Check cache first\n  const cached = _activeProfiles.get(userId);\n  if (cached) return cached;\n\n  // Check if user has profile-generated policies\n  const store = getPolicyStore();\n  const policies = store.listPolicies(userId);\n  const profilePolicy = policies.find(p => p.name.startsWith(PROFILE_POLICY_PREFIX));\n\n  if (profilePolicy) {\n    const id = profilePolicy.name.replace(PROFILE_POLICY_PREFIX, '') as ProfileId;\n    if (PROFILES[id]) {\n      _activeProfiles.set(userId, id);\n      return id;\n    }\n  }\n\n  // Check if user has any custom policies\n  if (policies.length > 0) {\n    _activeProfiles.set(userId, 'custom');\n    return 'custom';\n  }\n\n  // No policies at all = supervised\n  _activeProfiles.set(userId, 'supervised');\n  return 'supervised';\n}\n\n/**\n * Activate a profile for a user.\n *\n * - Removes any existing profile-generated policies.\n * - Creates new policies from the profile template.\n * - Does NOT compile to on-chain delegation (use /delegate create after).\n * - Returns the created policies (empty for supervised/custom).\n */\nexport function activateProfile(\n  userId: string,\n  profileId: ProfileId,\n): { profile: AutonomyProfile; policies: Policy[] } {\n  const profile = PROFILES[profileId];\n  if (!profile) throw new Error(`Unknown profile: ${profileId}`);\n\n  const store = getPolicyStore();\n\n  // Remove existing profile-generated policies\n  const existing = store.listPolicies(userId);\n  for (const p of existing) {\n    if (p.name.startsWith(PROFILE_POLICY_PREFIX)) {\n      store.deletePolicy(userId, p.id);\n    }\n  }\n\n  // Create policies from profile template\n  const created: Policy[] = [];\n\n  if (profile.rules.length > 0) {\n    const now = Date.now();\n    const hasCategories = profile.scopeCategories.length > 0;\n    const scope: PolicyScope = {\n      type: hasCategories ? 'categories' : 'all_write',\n      tools: undefined,\n      categories: hasCategories ? profile.scopeCategories : undefined,\n    };\n\n    const policy: Policy = {\n      id: randomUUID(),\n      name: `${PROFILE_POLICY_PREFIX}${profileId}`,\n      description: `${profile.name} profile — ${profile.description}`,\n      rules: profile.rules,\n      scope,\n      status: 'active',\n      confirmedAt: now,\n      createdAt: now,\n      updatedAt: now,\n      userId,\n    };\n\n    store.savePolicy(policy);\n    created.push(policy);\n  }\n\n  _activeProfiles.set(userId, profileId);\n  return { profile, policies: created };\n}\n\n/**\n * Deactivate a profile — removes profile-generated policies.\n * Reverts to supervised.\n */\nexport function deactivateProfile(userId: string): void {\n  const store = getPolicyStore();\n  const existing = store.listPolicies(userId);\n  for (const p of existing) {\n    if (p.name.startsWith(PROFILE_POLICY_PREFIX)) {\n      store.deletePolicy(userId, p.id);\n    }\n  }\n  _activeProfiles.set(userId, 'supervised');\n}\n\n/** Format a profile for display. */\nexport function formatProfileDisplay(profile: AutonomyProfile, isActive: boolean): string {\n  const lines: string[] = [];\n  const marker = isActive ? ' (active)' : '';\n  lines.push(`**${profile.name}**${marker} — \\`/profile ${profile.id}\\``);\n  for (const s of profile.summary) {\n    lines.push(`  ${s}`);\n  }\n  return lines.join('\\n');\n}\n\n/** Reset profile cache (for testing). */\nexport function resetProfileCache(): void {\n  _activeProfiles.clear();\n}\n"],"mappings":"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"}