diff --git a/server.py b/server.py index 879e540..3e71f80 100644 --- a/server.py +++ b/server.py @@ -122,6 +122,13 @@ class GlobalConfig: EMAIL_HTML_SIGNATURE: str = "" + # LLM identity defaults (can be overridden per-call via signature_vars) + LLM_NAME: str = os.getenv("LLM_NAME", "") + LLM_TITLE: str = os.getenv("LLM_TITLE", "") + LLM_PHONE: str = os.getenv("LLM_PHONE", "") + LLM_ADDRESS: str = os.getenv("LLM_ADDRESS", "") + LLM_EMAIL: str = os.getenv("LLM_EMAIL", "") + @classmethod def resolve_html_signature(cls, raw: str) -> str: if not raw: @@ -136,6 +143,32 @@ class GlobalConfig: # Otherwise, treat as inline HTML return raw.strip() + @staticmethod + def render_signature_with_vars(signature_template: str, override_vars: Optional[Dict[str, str]] = None) -> str: + """ + Replace {{NAME}}, {{TITLE}}, {{PHONE}}, {{ADDRESS}}, {{EMAIL}} in signature_template + using env-based defaults or per-call overrides. + """ + if not signature_template: + return signature_template + + if override_vars is None: + override_vars = {} + + name = override_vars.get("NAME") or os.getenv("LLM_NAME", "") + title = override_vars.get("TITLE") or os.getenv("LLM_TITLE", "") + phone = override_vars.get("PHONE") or os.getenv("LLM_PHONE", "") + address = override_vars.get("ADDRESS") or os.getenv("LLM_ADDRESS", "") + email = override_vars.get("EMAIL") or os.getenv("LLM_EMAIL", "") + + out = signature_template + out = out.replace("{{NAME}}", name) + out = out.replace("{{TITLE}}", title) + out = out.replace("{{PHONE}}", phone) + out = out.replace("{{ADDRESS}}", address) + out = out.replace("{{EMAIL}}", email) + return out + @property def personnel(self) -> List[Dict[str, Any]]: try: @@ -1097,9 +1130,20 @@ TOOLS = [ "body": {"type": "string"}, "cc": {"type": "array", "items": {"type": "string"}}, "bcc": {"type": "array", "items": {"type": "string"}}, - "html": {"type": "boolean", "description": "Treat body as HTML"}, + "html": {"type": "boolean", "description": "Treat body as HTML (default: true)"}, "in_reply_to": {"type": "string"}, - "references": {"type": "string"} + "references": {"type": "string"}, + "signature_vars": { + "type": "object", + "description": "Optional identity variables for signature template (NAME, TITLE, PHONE, ADDRESS, EMAIL)", + "properties": { + "NAME": {"type": "string"}, + "TITLE": {"type": "string"}, + "PHONE": {"type": "string"}, + "ADDRESS": {"type": "string"}, + "EMAIL": {"type": "string"} + } + } }, "required": ["to", "subject", "body"] } @@ -1114,10 +1158,21 @@ TOOLS = [ "folder": {"type": "string"}, "uid": {"type": "integer"}, "body": {"type": "string"}, - "html": {"type": "boolean"}, + "html": {"type": "boolean", "description": "Treat body as HTML (default: true)"}, "to": {"type": "array", "items": {"type": "string"}, "description": "Override reply recipients"}, "cc": {"type": "array", "items": {"type": "string"}}, - "bcc": {"type": "array", "items": {"type": "string"}} + "bcc": {"type": "array", "items": {"type": "string"}}, + "signature_vars": { + "type": "object", + "description": "Optional identity variables for signature template (NAME, TITLE, PHONE, ADDRESS, EMAIL)", + "properties": { + "NAME": {"type": "string"}, + "TITLE": {"type": "string"}, + "PHONE": {"type": "string"}, + "ADDRESS": {"type": "string"}, + "EMAIL": {"type": "string"} + } + } }, "required": ["folder", "uid", "body"] } @@ -1135,7 +1190,18 @@ TOOLS = [ "cc": {"type": "array", "items": {"type": "string"}}, "bcc": {"type": "array", "items": {"type": "string"}}, "note": {"type": "string", "description": "Optional note to prepend"}, - "html": {"type": "boolean"} + "html": {"type": "boolean", "description": "Treat body as HTML (default: true)"}, + "signature_vars": { + "type": "object", + "description": "Optional identity variables for signature template (NAME, TITLE, PHONE, ADDRESS, EMAIL)", + "properties": { + "NAME": {"type": "string"}, + "TITLE": {"type": "string"}, + "PHONE": {"type": "string"}, + "ADDRESS": {"type": "string"}, + "EMAIL": {"type": "string"} + } + } }, "required": ["folder", "uid", "to"] } @@ -1209,10 +1275,21 @@ TOOLS = [ "body": {"type": "string"}, "cc": {"type": "array", "items": {"type": "string"}}, "bcc": {"type": "array", "items": {"type": "string"}}, - "html": {"type": "boolean"}, + "html": {"type": "boolean", "description": "Treat body as HTML (default: true)"}, "send_at": {"type": "number", "description": "Unix timestamp when to send"}, "in_reply_to": {"type": "string"}, - "references": {"type": "string"} + "references": {"type": "string"}, + "signature_vars": { + "type": "object", + "description": "Optional identity variables for signature template (NAME, TITLE, PHONE, ADDRESS, EMAIL)", + "properties": { + "NAME": {"type": "string"}, + "TITLE": {"type": "string"}, + "PHONE": {"type": "string"}, + "ADDRESS": {"type": "string"}, + "EMAIL": {"type": "string"} + } + } }, "required": ["to", "subject", "body", "send_at"] } @@ -1631,8 +1708,13 @@ def send_email_impl(args): html = True body = args["body"] + + # Use LLM-provided identity if present + signature_vars = args.get("signature_vars") or {} + if html and config.EMAIL_HTML_SIGNATURE: - body = body.rstrip("\n") + "\n" + config.EMAIL_HTML_SIGNATURE + sig = GlobalConfig.render_signature_with_vars(config.EMAIL_HTML_SIGNATURE, signature_vars) + body = body.rstrip("\n") + "\n" + sig try: send_email( @@ -1660,8 +1742,13 @@ def schedule_send_impl(args): html = True body = args["body"] + + # Use LLM-provided identity if present + signature_vars = args.get("signature_vars") or {} + if html and config.EMAIL_HTML_SIGNATURE: - body = body.rstrip("\n") + "\n" + config.EMAIL_HTML_SIGNATURE + sig = GlobalConfig.render_signature_with_vars(config.EMAIL_HTML_SIGNATURE, signature_vars) + body = body.rstrip("\n") + "\n" + sig task_id = add_scheduled_send( account_id=account_id, @@ -1678,7 +1765,7 @@ def schedule_send_impl(args): return {"status": "scheduled", "task_id": task_id, "account": account_id} -def reply_to_message_impl(account=None, folder=None, uid=None, body=None, html=None, to=None, cc=None, bcc=None): +def reply_to_message_impl(account=None, folder=None, uid=None, body=None, html=None, to=None, cc=None, bcc=None, signature_vars=None): acc = get_account(account) imap = create_imap(acc) try: @@ -1712,7 +1799,8 @@ def reply_to_message_impl(account=None, folder=None, uid=None, body=None, html=N # Append HTML signature if sending as HTML if html and config.EMAIL_HTML_SIGNATURE: - body = (body or "").rstrip("\n") + "\n" + config.EMAIL_HTML_SIGNATURE + sig = GlobalConfig.render_signature_with_vars(config.EMAIL_HTML_SIGNATURE, signature_vars or {}) + body = (body or "").rstrip("\n") + "\n" + sig send_email( acc=acc, @@ -1730,7 +1818,7 @@ def reply_to_message_impl(account=None, folder=None, uid=None, body=None, html=N imap.logout() -def forward_message_impl(account=None, folder=None, uid=None, to=None, cc=None, bcc=None, note="", html=None, body=None): +def forward_message_impl(account=None, folder=None, uid=None, to=None, cc=None, bcc=None, note="", html=None, body=None, signature_vars=None): acc = get_account(account) imap = create_imap(acc) try: @@ -1756,7 +1844,8 @@ def forward_message_impl(account=None, folder=None, uid=None, to=None, cc=None, # Append HTML signature if sending as HTML if html and config.EMAIL_HTML_SIGNATURE: - body = body.rstrip("\n") + "\n" + config.EMAIL_HTML_SIGNATURE + sig = GlobalConfig.render_signature_with_vars(config.EMAIL_HTML_SIGNATURE, signature_vars or {}) + body = body.rstrip("\n") + "\n" + sig send_email( acc=acc,