# promptmask.config.default.toml

# Configuration for the local LLM used for masking.
# Environment variables like LOCALAI_API_BASE and LOCALAI_API_KEY are checked first.
[llm_api]
base = "http://localhost:11434/v1"
model = "" # If empty, will auto-detect first available model from /v1/models
key = ""
timeout = 15.0

# Defines what data is considered sensitive.
[sensitive]
# A natural language description of data categories to mask.
# This will be injected into the system prompt for the local LLM.
include = "personally identifiable information (PII), Credentials/Authentication Data"
# A natural language description of data categories to explicitly ignore.
exclude = "general information"

# Defines the mask format.
[mask_wrapper]
left = "${"
right = "}"

[model_specific]
dual_models = ["qwen3", "smollm3", "glm-4.5"]
dual_metaprompt = "/no_think\n" # /nothink for glm-4.5

# System prompt engineering for the local masking LLM.
[prompt]
system_template = """You are a Data Masking API that maps all unique mask names to the original value of sensitive data in the user input.
Make sure masks are unique and non-overlapping.

Config:
- Do mask: ${sensitive_include}
- Do not mask: ${sensitive_exclude}
- Granularity: Masking only works at the word and phrase levels, never at the sentence or paragraph levels
- Mask format: ${mask_left}DESCRPTIVE_MASK_NAME${mask_right}

Request format constrains:
- Tag-Wrapped: The raw content of user input is wrapped inside a <user_input_text> tag
- Types: Content inside <user_input_text> can be in any type (data, code, text) and could contain sensitive data that need masking

Response format constrains:
- JSON Mode: Response MUST be a single, flattend, valid JSON object wrapped inside a <mask_mapping> tag
- Type Safety: `assert all(type(value)=="string" for value of json.loads(masking_mapping).values())`
- Edge Case: If no sensitive data is found, respond with an empty JSON object: <mask_mapping>{}</mask_mapping>
- Example: <mask_mapping>{"${mask_left}USER_EMAIL${mask_right}":"test@example.com", "${mask_left}USER_PASSWORD${mask_right}":"P@ssword123!"}</mask_mapping>"""

examples = [
    { role = "user", content = "<user_input_text>\nMy account ID is 4567, and my credit card number is 1234-5678-9012-3456. Call me at +1 (456) 789 1234.\n</user_input_text>" },
    { role = "assistant", content = "<mask_mapping>{\"${mask_left}USER_ACCOUNT_ID${mask_right}\":\"4567\", \"${mask_left}USER_CREDIT_CARD_NUMBER${mask_right}\":\"1234-5678-9012-3456\", \"${mask_left}USER_PHONE_NUMBER${mask_right}\":\"+1 (456) 789 1234\"}</mask_mapping>" },
    { role = "user", content = """<user_input_text>
[
  {
    "users": [
      {"name": "Chan Ho Yin", "ip": "203.0.113.45", "role": "admin", "phone_number": "+852 9123 4567"},
      {"name": "Priya Sharma", "email": "priya.sharma@corp.com", "role": "editor", "device_id": "DEVICE-XYZ-789"}
    ],
    "log_entry": "Login attempt by priya.sharma@corp.com from IP 203.0.113.45 was approved by admin Chan Ho Yin."
  },
  {
    "users": [
      {"name": "Javier Rodriguez", "date_of_birth": "1988-03-15", "role": "viewer", "employee_id": "EMP-1002"},
      {"name": "Li Wei", "passport_id": "G12345678", "role": "developer", "department": "R&D"}
    ],
    "log_entry": "Access granted to user Li Wei (EMP-1002, R&D) after verification by Javier Rodriguez (DOB 1988-03-15). Passport G12345678 used."
  }
]
</user_input_text>""" },
    { role = "assistant", content = "<mask_mapping>{\"${mask_left}USER_1_NAME${mask_right}\":\"Chan Ho Yin\", \"${mask_left}USER_1_IP_ADDRESS${mask_right}\":\"203.0.113.45\", \"${mask_left}USER_1_PHONE_NUMBER${mask_right}\":\"+852 9123 4567\", \"${mask_left}USER_2_NAME${mask_right}\":\"Priya Sharma\", \"${mask_left}USER_2_EMAIL${mask_right}\":\"priya.sharma@corp.com\", \"${mask_left}USER_3_NAME${mask_right}\":\"Javier Rodriguez\", \"${mask_left}USER_3_DATE_OF_BIRTH${mask_right}\":\"1988-03-15\", \"${mask_left}USER_4_NAME${mask_right}\":\"Li Wei\", \"${mask_left}USER_4_PASSPORT_ID${mask_right}\":\"G12345678\"}</mask_mapping>" },
    { role = "user", content = "<user_input_text>\nHow are you?\n</user_input_text>" },
    { role = "assistant", content = "<mask_mapping>{}</mask_mapping>" },
    { role = "user", content = """<user_input_text>
import os,requests
auth_token, pub_key = "sk-abcdef", "pk-12345"
database_url = "postgres://admin:db_pass_123!@db.internal.net:5432/production"
data = requests.get('https://api.service.com/v1/data', headers={'Authorization': f'Bearer {auth_token}'}).json()
</user_input_text>""" },
    { role = "assistant", content = "<mask_mapping>{\"${mask_left}MY_AUTH_TOKEN${mask_right}\":\"sk-abcdef\", \"${mask_left}MY_DB_CONNECTION_URL${mask_right}\":\"postgres://admin:db_pass_123!@db.internal.net:5432/production\"}</mask_mapping>" }
]

user_template = "<user_input_text>\n${text_to_mask}\n</user_input_text>"


# This is only for the optional web API
[web]
upstream_oai_api_base="http://api.openai.com/v1"

# General settings
[general]
verbose = false