{
  "agentAName": "M-Phone API Test Receptionist",
  "fixedGreeting": {
    "en": "Hello, this is the M-Phone API test line. Tell me which test to run: send a message, leave a call note, list, book, read, change or cancel an appointment, ring the Accounts department, or connect me to Soon Keat.",
    "ms": "",
    "zh": ""
  },
  "agentAReturnedGreeting": {
    "en": "",
    "ms": "",
    "zh": ""
  },
  "instructions": {
    "en": "You are a TEST receptionist whose only job is to exercise the M-Phone phone-system API through your tools. Do exactly what the caller asks, one tool call per request, and report the outcome plainly.\n\nFIXED TEST VALUES (from REFERENCE DATA): the test person is extension 8704 (Soon Keat). The test department is Accounts. The caller's number is [CALLERPHONE]; use it as caller_number everywhere. If the caller gives a name, use it as caller_name, otherwise use \"Test Caller\". Today is [CURRENTDATE] ([CURRENTTIME], Malaysia).\n\nTIME RULES: every time you send must be ISO 8601 WITH the Malaysia offset, like 2026-10-02T15:00:00+08:00. Never send a time without +08:00. \"Tomorrow 3pm\" means tomorrow's date from [CURRENTDATE] at 15:00:00+08:00. Appointments default to 30 minutes.\n\nTEST FLOW (the caller may ask for any step in any order):\n1. \"send a message\" -> mphone_send_message with type message_left and the text the caller dictates (ask for the text if not given). \"send a note\" -> type note (no caller_number needed). The phone system writes transferred and missed_call cards by itself, so send those types ONLY if the caller literally says \"force a transferred card\" or \"force a missed call card\".\n2. \"leave a call note\" -> mphone_call_note with a one-line reason the caller gives.\n3. \"list appointments\" -> mphone_list_appointments for extension 8704; if the caller names a day, pass from/to covering that whole day; say \"include cancelled\" -> include_cancelled 1.\n4. \"book an appointment\" -> mphone_book_appointment. Ask for the day and time if missing. Send duration_minutes 30 unless the caller gives a length or an end time; if they give an end time send end instead of duration_minutes, never both. After booking, READ THE APPOINTMENT ID BACK TO THE CALLER slowly (for example \"a underscore 12\") and remember it for later steps.\n5. \"read appointment\" -> mphone_get_appointment with the id you remembered, or the id the caller gives. Report its status and who decided.\n6. \"change the appointment\" -> mphone_change_appointment with the id and ONLY the fields that change (usually start). Read back the new time and status.\n7. \"cancel the appointment\" -> mphone_cancel_appointment with the id.\n8. \"ring Accounts\" or \"ring the department\" -> dial_department with department Accounts and a one-line reason.\n9. \"connect me to Soon Keat\" -> dial_extension with extension 8704, name Soon Keat, a one-line reason (what the caller wants, no phone number) and details (fuller story).\n\nREPORTING RULES (this is a test line, so be explicit): after each tool result say whether it succeeded, and read out the key fields the API returned: ok, id, status, delivered, valid_seconds. If the API returned an error, read the status code and the error text exactly. Do not invent results. Do not call a tool the caller did not ask for. Keep every reply to two short sentences plus the readout.\n\nIf an appointment time is taken (409), say so and offer the next free half hour.",
    "ms": "",
    "zh": ""
  },
  "agentData": "M-PHONE API TEST DATA\n- Test person: extension 8704, name Soon Keat, department Accounts, status ONLINE.\n- Test department: Accounts.\n- Base address: https://ai.mforce.asia (API key is in each tool's x_headers).\n- Appointment ids look like a_12. Message ids look like m_123.\n- Appointment statuses: waiting (person has not decided), confirmed, cancelled, done. decided_by is person, ai, or empty.\n- Message types: note, message_left, missed_call, transferred. caller_number is required for every type except note.\n- Call notes are used for the NEXT transfer of this caller to this person within 60 seconds, one time.\n- Do NOT send transferred or missed_call cards in normal use: the phone system writes them itself when a call is passed to one person. They exist in the test profile only for an explicit forced test.\n- call_id and time are left out of every tool on purpose: the AI has no truthful source for them (server defaults apply).",
  "enableOmni": true,
  "omniModel": "qwen3.5-omni-plus-realtime",
  "omniVoice": "Serena",
  "omniSpeechStyle": "Clear, neutral, slightly slower than normal so test readouts are easy to hear.",
  "omniBargeInRms": "0.030",
  "omniSmoothBargeIn": true,
  "noiseSuppression": "off",
  "sttProvider": "qwen",
  "geminiModel": "",
  "geminiLangHint": [],
  "vadThreshold": "0.2",
  "silenceDuration": "800",
  "vadType": "server_vad",
  "prefixPaddingMs": "",
  "idleTimeoutMs": "",
  "bargeInMinDuration": "300",
  "idleTimeoutEnabled": false,
  "idleTimeoutSeconds": "30",
  "llmModel": "qwen3.5-flash",
  "temperature": "0.30",
  "maxTokens": "300",
  "topP": "0.90",
  "enableThinking": false,
  "ttsMode": "streaming",
  "toolRouting": "full",
  "functionsTextarea": "[\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"mphone_send_message\",\n      \"description\": \"Put a card into the person's Messages > AI receptionist in the M-Phone app. Normal use: type note (a plain line from the AI) or message_left (a message the AI took for the person). The phone system writes transferred and missed_call cards BY ITSELF when a call is passed to one person, so only send those two types when the caller explicitly asks to force one for testing.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"extension\": {\n            \"type\": \"string\",\n            \"description\": \"The person's extension, 2 to 6 digits. Test value: 8704.\"\n          },\n          \"type\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"note\",\n              \"message_left\",\n              \"missed_call\",\n              \"transferred\"\n            ],\n            \"description\": \"note or message_left in normal use. transferred / missed_call are system-written; send them only on an explicit 'force' request.\"\n          },\n          \"caller_number\": {\n            \"type\": \"string\",\n            \"description\": \"Caller's number in E.164, e.g. +60123456789. Required for every type except note.\"\n          },\n          \"caller_name\": {\n            \"type\": \"string\",\n            \"description\": \"Caller's name if known, at most 80 characters.\"\n          },\n          \"text\": {\n            \"type\": \"string\",\n            \"description\": \"Plain text, at most 1000 characters. Required for note and message_left.\"\n          }\n        },\n        \"required\": [\n          \"extension\",\n          \"type\"\n        ]\n      }\n    },\n    \"x_endpoint\": \"https://ai.mforce.asia/api/ai/v1/messages\",\n    \"x_method\": \"POST\",\n    \"x_headers\": {\n      \"Authorization\": \"Bearer mpk_YOUR-API-KEY\"\n    }\n  },\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"mphone_call_note\",\n      \"description\": \"Leave a one-line reason with the phone system BEFORE passing the call to a person. It is shown on that person's ringing phone the next time this caller is transferred to them within 60 seconds, one time.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"extension\": {\n            \"type\": \"string\",\n            \"description\": \"The person the call will go to. Test value: 8704.\"\n          },\n          \"caller_number\": {\n            \"type\": \"string\",\n            \"description\": \"Caller's number in E.164.\"\n          },\n          \"reason\": {\n            \"type\": \"string\",\n            \"description\": \"One line, at most 200 characters: what the caller wants. No phone number.\"\n          },\n          \"caller_name\": {\n            \"type\": \"string\",\n            \"description\": \"Caller's name if known.\"\n          }\n        },\n        \"required\": [\n          \"extension\",\n          \"caller_number\",\n          \"reason\"\n        ]\n      }\n    },\n    \"x_endpoint\": \"https://ai.mforce.asia/api/ai/v1/call-notes\",\n    \"x_method\": \"POST\",\n    \"x_headers\": {\n      \"Authorization\": \"Bearer mpk_YOUR-API-KEY\"\n    }\n  },\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"mphone_list_appointments\",\n      \"description\": \"Read a person's appointments to find a free time. Sorted by start, cancelled ones left out unless include_cancelled is 1.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"extension\": {\n            \"type\": \"string\",\n            \"description\": \"The person. Test value: 8704.\"\n          },\n          \"from\": {\n            \"type\": \"string\",\n            \"description\": \"Only appointments ending at or after this time. ISO 8601 with +08:00.\"\n          },\n          \"to\": {\n            \"type\": \"string\",\n            \"description\": \"Only appointments starting at or before this time. ISO 8601 with +08:00.\"\n          },\n          \"include_cancelled\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"1\"\n            ],\n            \"description\": \"Send 1 to include cancelled appointments.\"\n          }\n        },\n        \"required\": [\n          \"extension\"\n        ]\n      }\n    },\n    \"x_endpoint\": \"https://ai.mforce.asia/api/ai/v1/appointments\",\n    \"x_method\": \"GET\",\n    \"x_headers\": {\n      \"Authorization\": \"Bearer mpk_YOUR-API-KEY\"\n    }\n  },\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"mphone_get_appointment\",\n      \"description\": \"Read one appointment by id to see whether the person confirmed or cancelled it. Works for every status.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"string\",\n            \"description\": \"Appointment id, e.g. a_12.\"\n          }\n        },\n        \"required\": [\n          \"id\"\n        ]\n      }\n    },\n    \"x_endpoint\": \"https://ai.mforce.asia/api/ai/v1/appointments/{id}\",\n    \"x_method\": \"GET\",\n    \"x_headers\": {\n      \"Authorization\": \"Bearer mpk_YOUR-API-KEY\"\n    }\n  },\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"mphone_book_appointment\",\n      \"description\": \"Book a time with a person. The phone system shows the person a New appointment card with a Check button. Status starts as waiting until the person decides. Exactly one of end or duration_minutes must be sent.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"extension\": {\n            \"type\": \"string\",\n            \"description\": \"The person the appointment is with. Test value: 8704.\"\n          },\n          \"title\": {\n            \"type\": \"string\",\n            \"description\": \"Short title, at most 120 characters.\"\n          },\n          \"start\": {\n            \"type\": \"string\",\n            \"description\": \"Start time, ISO 8601 with +08:00, e.g. 2026-10-02T15:00:00+08:00.\"\n          },\n          \"duration_minutes\": {\n            \"type\": \"integer\",\n            \"description\": \"Length in minutes, 1 to 1440. Send duration_minutes OR end. Use 30 when the caller gives no length or end time.\"\n          },\n          \"caller_number\": {\n            \"type\": \"string\",\n            \"description\": \"Number to call back, E.164.\"\n          },\n          \"caller_name\": {\n            \"type\": \"string\",\n            \"description\": \"Who the appointment is with.\"\n          },\n          \"note\": {\n            \"type\": \"string\",\n            \"description\": \"Longer text, at most 1000 characters.\"\n          },\n          \"end\": {\n            \"type\": \"string\",\n            \"description\": \"End time, ISO 8601 with +08:00, at most 24 hours after start. Send end OR duration_minutes, not both.\"\n          }\n        },\n        \"required\": [\n          \"extension\",\n          \"title\",\n          \"start\",\n          \"caller_number\"\n        ]\n      }\n    },\n    \"x_endpoint\": \"https://ai.mforce.asia/api/ai/v1/appointments\",\n    \"x_method\": \"POST\",\n    \"x_headers\": {\n      \"Authorization\": \"Bearer mpk_YOUR-API-KEY\"\n    }\n  },\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"mphone_change_appointment\",\n      \"description\": \"Change an existing appointment. Send only the fields that change. A new start time sets the status back to waiting. The extension cannot be changed.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"string\",\n            \"description\": \"Appointment id, e.g. a_12.\"\n          },\n          \"title\": {\n            \"type\": \"string\",\n            \"description\": \"New title, if it changes.\"\n          },\n          \"start\": {\n            \"type\": \"string\",\n            \"description\": \"New start time, ISO 8601 with +08:00. The length stays the same unless duration_minutes is also sent.\"\n          },\n          \"duration_minutes\": {\n            \"type\": \"integer\",\n            \"description\": \"New length in minutes, if it changes.\"\n          },\n          \"caller_name\": {\n            \"type\": \"string\",\n            \"description\": \"New caller name, if it changes.\"\n          },\n          \"caller_number\": {\n            \"type\": \"string\",\n            \"description\": \"New call-back number, if it changes.\"\n          },\n          \"note\": {\n            \"type\": \"string\",\n            \"description\": \"New note, if it changes.\"\n          },\n          \"end\": {\n            \"type\": \"string\",\n            \"description\": \"New end time, ISO 8601 with +08:00, if it changes. Do not send both end and duration_minutes.\"\n          }\n        },\n        \"required\": [\n          \"id\"\n        ]\n      }\n    },\n    \"x_endpoint\": \"https://ai.mforce.asia/api/ai/v1/appointments/{id}\",\n    \"x_method\": \"PUT\",\n    \"x_headers\": {\n      \"Authorization\": \"Bearer mpk_YOUR-API-KEY\"\n    }\n  },\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"mphone_cancel_appointment\",\n      \"description\": \"Cancel an appointment by id. It disappears from the person's calendar. Cancelling an already cancelled one answers the same way.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"string\",\n            \"description\": \"Appointment id, e.g. a_12.\"\n          }\n        },\n        \"required\": [\n          \"id\"\n        ]\n      }\n    },\n    \"x_endpoint\": \"https://ai.mforce.asia/api/ai/v1/appointments/{id}\",\n    \"x_method\": \"DELETE\",\n    \"x_headers\": {\n      \"Authorization\": \"Bearer mpk_YOUR-API-KEY\"\n    }\n  },\n  {\n    \"type\": \"function\",\n    \"function\": {\n      \"name\": \"dial_department\",\n      \"description\": \"Ring every free phone of a whole department and pass the call to whoever answers. Use when the caller wants a department rather than one person.\",\n      \"parameters\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"department\": {\n            \"type\": \"string\",\n            \"description\": \"Department name exactly as in REFERENCE DATA. Test value: Accounts.\"\n          },\n          \"reason\": {\n            \"type\": \"string\",\n            \"description\": \"Always include this: one line, at most 200 characters, what the caller wants, shown on the ringing phones. No phone number.\"\n          },\n          \"details\": {\n            \"type\": \"string\",\n            \"description\": \"Optional fuller explanation, at most 2000 characters.\"\n          }\n        },\n        \"required\": [\n          \"department\"\n        ]\n      }\n    }\n  }\n]",
  "transferAgents": [],
  "transferDelay": "1.5",
  "speechRate": "1.0",
  "pitchRate": "1.0",
  "ttsVolume": "100",
  "enableLanguageAgent": false,
  "languageAgentGreeting": "",
  "languageAgentInstructions": "",
  "voiceMap": {
    "default": "Ethan",
    "en": "Ethan",
    "ms": "Ethan",
    "zh": "Cherry"
  },
  "omniVoiceMap": {
    "default": "Serena",
    "en": "Serena",
    "ms": "Serena",
    "zh": "Serena"
  },
  "acrs": {
    "enabled": false
  },
  "conversationValidator": {
    "enabled": false
  },
  "emotionConfig": {
    "enabled": false,
    "engine_url": ""
  },
  "allowedLanguages": [
    "en"
  ],
  "variableMappings": [],
  "disabledBuiltinTools": [],
  "placeholderFields": {},
  "wsUrl": "ws://localhost:8767"
}
