CodeGeeX-4
CodeGeeX4 היא משפחת מודלי תכנות רב־לשונית ליצירת קוד, להשלמה, להסבר, לתיקון ולשאלות על מאגרי קוד. המדריכים המקוריים שלה כוללים הנחיות ייעודיות למשימה, מילוי פערים בין חלקי קוד קיימים ושימוש בקבצים קשורים להכנת שינויים עם נתיבי קבצים מפורשים.
- Ailoot Ultra · OpenAI Chat
POST /v1/chat/completionscodegeex-4 - Ailoot Ultra · Anthropic Messages
POST /v1/messagescodegeex-4
על המודל
התיאור הזה מציג את יכולות המודל. הקלט, הפלט והאפשרויות הזמינים ב-Ailoot מפורטים בהמשך לפי השיטה שנבחרה.
CodeGeeX4 היא משפחת מודלי תכנות רב־לשונית שנבנתה לסיוע בתכנות ולעבודה בין קובצי מקור קשורים. היצרן מפרסם את CodeGeeX4-ALL-9B כחבר קוד פתוח בסדרה, שפותח באמצעות אימון המשך של GLM-4-9B. התיעוד שלה כולל יצירת קוד והשלמתו, שאלות תכנות, ניתוח מאגרי קוד ותהליכים מחוברים הכוללים מפרש קוד, חיפוש ברשת או קריאות לפונקציות. הפלט הרגיל הוא טקסט: קוד, הסברים, תשובות או שינויים המסומנים לפי קבצים, בהתאם להוראת המשימה.
התחילו בבחירת הפעולה ובמסירת הקוד שהמודל צריך. מדריך הנחיות המערכת המקורי כולל הוראות נפרדות להוספת הערות, להסבר תוכנית, לתרגום בין שפות תכנות, לבדיקת קוד או לתיקונו, ליצירת בדיקות ולמענה לשאלות על קובץ. לתיקון, כללו את הקוד הנכשל, את ההתנהגות שנצפתה ואת התוצאה הרצויה. לתרגום, ציינו לאיזו שפת תכנות יש לתרגם וספקו את כל הפונקציה הרלוונטית. להערות, הוראת המשימה של היצרן משמרת את הקוד ומוסיפה הערות; בכמה משימות המפיקות קוד היא מבקשת קוד בלבד. הבחנות אלה מסייעות להפוך את התוצאה לתוצר קוד או להסבר שימושיים, במקום להשאיר את פורמט הפלט משתמע.
המדריכים מספקים הנחיות מערכת בסינית ובאנגלית. שפת הוראת המערכת אינה קובעת כשלעצמה את שפת התשובה, ולכן בקשו במפורש את שפת התגובה כאשר דרוש הסבר. הנחיות הבדיקה הייעודיות מתארות פלט בסינית; הנחיית עוזר התכנות הכללית מספקת דרך נפרדת לבקש בדיקה בשפת תגובה אחרת. חלק מתבניות המשימה מגדירות ששפת ההערות תתאים למקור ומונעות פלט המערב סינית ואנגלית. בשיחה מתמשכת, חזרו על הוראת המשימה הרלוונטית בעת החלפת פעולות, כדי שבקשה להסבר לא תתבלבל עם הבקשה הקודמת לפלט קוד בלבד.
להשלמה לפי הקשר, הפורמט המקורי מתאר את קובץ היעד, את שפת התכנות שלו ואת הקוד משני צידי נקודת ההוספה. השתמשו בנתיב הקובץ היחסי עם ###PATH: וכללו ###LANGUAGE:; המדריך מאפשר ערך שפה ריק כשאינה ידועה. ###MODE: בוחר LINE להשלמת שורה אחת או BLOCK לכמה שורות, כאשר BLOCK הוא ברירת המחדל המתועדת. ברצף מילוי האמצע מופיעה קודם הסיומת, אחריה הקידומת ואז האמצע החסר, המסומנים ב־<|code_suffix|>, <|code_prefix|> ו־<|code_middle|>. תבנית המילוי של היצרן משמיטה את הנחיית המערכת. שמירת הסיומת נותנת למודל את זרימת הבקרה שסביב ואת הקוד שחייב להישאר אחרי ההוספה. התוצאה היא הקוד החסר המוצע, שניתן לבדוק במיקומו המקורי.
השלמה חוצת קבצים מוסיפה קטעים קשורים כחומר עיון, כאשר כל אחד מתחיל ב־###REFERENCE: וב־###PATH: משלו. שמרו מקורות אלה בנפרד מקובץ היעד ומנקודת ההוספה שלו. לדוגמה, בהשלמת פונקציה הקוראת לפונקציית עזר קיימת, ספקו את החתימה והמימוש של פונקציית העזר לצד הקידומת והסיומת של פונקציית היעד. מדריך ההשלמה ברמת הפרויקט מרחיב גישה זו ליצירת קובץ חדש מדרישות הפרויקט ומקוד קיים רלוונטי. נתיבים ברורים ותלויות נבחרות מאפשרים להבחין בין קוד שסופק כראיה לבין הקובץ שהמודל מתבקש להשלים.
שאלות על מאגר משתמשות במבנה מקורי אחר: רשמו כל קובץ תחת ###PATH:, כללו את הקוד שלו ואז שאלו את השאלה. הנחיה שימושית יכולה לשאול היכן מוגדר ערך או איך קריאה עוברת בין המודולים שסופקו. עריכת מאגר משתמשת בהוראת מערכת משלה להוספת קבצים, למחיקתם או לשינויים בהם, ומבקשת פלט בצורת ###PATH: {PATH} ואחריו הקוד. הכינו את הקבצים הרלוונטיים ותארו את השינוי הנדרש, לרבות הקובץ שיש להוסיף או ההתנהגות שיש לשמר. קראו את הבלוקים המוחזרים המסומנים בנתיב כשינויים מוצעים; הם אינם ראיה שמאגר כבר שונה או שהקוד הורץ.
לחבר CodeGeeX4-ALL-9B שפורסם, היצרן מתעד הקשר של 128K וממליץ לבחור תוכן רלוונטי מהמאגר כאשר פרויקט חורג מהחלון הזה. אחזור קטעים קשורים וצמצום קלטים גדולים מדי הם שלבי הכנה במדריך המאגר. ההקשר צריך להכיל את ההוראות, את הקוד שסופק ואת ההמשך שנוצר, ולכן קבוצת קבצים ממוקדת לרוב מועילה יותר משפיכה בלתי מובחנת של כל הפרויקט. הגדרות ההפקה שבדוגמת היצרן שולטות באורך ריצה מסוימת; הן אינן מגדירות אורך תשובה מרבי אוניברסלי לכל מהדורות CodeGeeX4.
הסדרה מתארת גם תהליכי תכנות מחוברים עם מפרשים, חיפוש וקריאות לפונקציות. תהליך כזה זקוק ליישום שיספק את הכלים הנקובים ויחזיר את תוצאותיהם לשיחה. כשמבקשים קוד שניתן להרצה, ציינו את השפה המיועדת, את התלויות ואת ההתנהגות הצפויה; כשמבקשים ניתוח, בקשו הפניות לקבצים או לפונקציות הרלוונטיים. הידרו או הריצו את השינויים המוצעים בסביבה המיועדת ובדקו את ההתנהגות מול הדרישה שסופקה לפני שילובם בפרויקט.
Ailoot Ultra · OpenAI Chat POST /v1/chat/completions codegeex-4
codegeex-4התחלה
CodeGeeX4 היא משפחת מודלי תכנות רב־לשונית ליצירת קוד, להשלמה, להסבר, לתיקון ולשאלות על מאגרי קוד. המדריכים המקוריים שלה כוללים הנחיות ייעודיות למשימה, מילוי פערים בין חלקי קוד קיימים ושימוש בקבצים קשורים להכנת שינויים עם נתיבי קבצים מפורשים.
- סוגי קלט נתמכים
- טקסט
- תוצאות
- טקסט
זמין ב-Ailoot · קלט ושיטות
Ailoot Ultra · OpenAI Chat POST /v1/chat/completions
- סוגי קלט
text- סוגי פלט
text- פורמט פלט
- json או SSE
| שדה | סוג | דרישה | ערכים ומגבלות | ברירת מחדל |
|---|---|---|---|---|
שדהmodel | סוגstring | דרישהחובה | ערכים ומגבלות codegeex-4 | ברירת מחדל— |
שדהmessages | סוגmessage[] | דרישהחובה | ערכים ומגבלות מספר פריטים מזערי: 1 | ברירת מחדל— |
שדהmessages[].role | סוגstring | דרישהחובה | ערכים ומגבלות תלוי במודל | ברירת מחדל— |
שדהmessages[].content | סוגstring | דרישהרשות | ערכים ומגבלות חל כאשר: שיחת טקסט | ברירת מחדל— |
שדהstream | סוגboolean | דרישהרשות | ערכים ומגבלות | ברירת מחדלfalse |
שילובים של חומרי קלט
טקסט · טקסט UTF8
messages[].content
פרמטרים ומחזור חיים של השיטה
| פרמטר | מפרט |
|---|---|
פרמטרcontent_type | מפרטapplication/json |
פרמטרrequired | מפרטmodel, messages |
פרמטרmaterial_types | מפרטtext |
פרמטרmessages | מפרטמערך הודעות במבנה role/content |
פרמטרfile_material | מפרטמסמך UTF-8 בפועל מוכנס כטקסט מילולי; לא מוסק מזהה קובץ |
פרמטרoptional_controls | מפרטstream |
פרמטרcontrol_scope | מפרטשיחת טקסט; stream הוא ערך בוליאני וברירת המחדל שלו היא false. |
פרמטרoutput_modalities | מפרטtext |
פרמטרhosted_operations | מפרטfalse |
פרמטרmultimodal_input_binding | מפרטnull |
כינויים לשיטה: /chat/completions
מחזור חיים: synchronous_or_streamed
שלחו את מזהה המודל המדויק עם messages.
אורך ההקשר אינו תקרת פלט.
קובץ טקסט יכול לספק טקסט מילולי; קלטי תמונה/אודיו/אובייקט קובץ דורשים קישור מדויק.
תעריפים
מידע תעריפים אינו מוסיף אפשרויות לבקשה. הפרמטרים הנתמכים מפורטים בשיטה שנבחרה.
- מצב מהיר
- לא צוין כאשר נבחר מצב מהיר
- מצב Flex
- לא צוין כאשר נבחר מצב flex
- מאמץ חשיבה מרבי
- לא צוין כאשר מאמץ החשיבה המרבי משתמש בהתאמת ברירת המחדל (default)
תעריפי Ailoot
מחירים לפי תצורה
| תצורה | טבלת תעריפים | חיוב |
|---|---|---|
| תצורהתעריפי הבסיס לטוקנים | טבלת תעריפיםתעריף בסיס | חיוב קלט · טוקני קלט $0.028 / 1K טוקנים פלט · טוקני פלט $0.028 / 1K טוקנים קלט · קריאה מהמטמון $0 / 1K טוקנים קלט · כתיבה למטמון $0 / 1K טוקנים קלט · כתיבה למטמון, 1 שעה — / 1K טוקנים |
לפני הבקשה Ailoot משריינת סכום משוער. לאחר קבלת התוצאה היא מסדירה את החיוב הסופי לפי השימוש המדוד. הסדרת חיוב בהזרמה משתמשת ברשומת השימוש הסופית. איך פועלים שריון הסכום והסדרת החיוב →
דוגמאות לבקשות
Ailoot Ultra · OpenAI Chat
set -eu
: "${AILOOT_API_KEY:?Set your Ailoot API key}"
python3 - <<'PY_REQUEST'
import json,os
from pathlib import Path
p=json.loads('{"model":"codegeex-4","messages":[{"role":"user","content":"hello"}],"stream":false}')
Path("request.json").write_text(json.dumps(p,ensure_ascii=False))
PY_REQUEST
curl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/chat/completions \
-H "Authorization: Bearer $AILOOT_API_KEY" -H 'Content-Type: application/json' \
--data-binary @request.json -D response-headers.txt -o result.json
python3 - <<'PY_RESULT'
import json
from pathlib import Path
r=json.loads(Path("result.json").read_text())
for x in r.get("choices",[]):
if x.get("message",{}).get("content"): print(x["message"]["content"])
PY_RESULT
from openai import OpenAI
import os
if not os.environ.get("AILOOT_API_KEY", "").strip(): raise SystemExit("Set AILOOT_API_KEY before making a request")
client=OpenAI(base_url="https://api.ailoot.ai/v1",api_key=os.environ["AILOOT_API_KEY"],max_retries=0)
result=client.chat.completions.create(model="codegeex-4", messages=[{"role":"user","content":"hello"}], stream=False)
import base64, json
from pathlib import Path
def save_result(data, stem="result"):
# Keep every field, including usage, IDs, reasoning and tool requests.
Path(stem + ".json").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
print(json.dumps(data, ensure_ascii=False, indent=2))
def save_blob(encoded, suffix, label):
raw = base64.b64decode(encoded, altchars=b"-_", validate=True)
ext = "png" if raw.startswith(b"\x89PNG\r\n\x1a\n") else "jpg" if raw.startswith(b"\xff\xd8") else "webp" if raw[:4] == b"RIFF" and raw[8:12] == b"WEBP" else suffix
file = Path(stem + "-" + label + "." + ext)
file.write_bytes(raw)
print("Saved", file)
for index, block in enumerate(data.get("content") or []):
print("Content", index, json.dumps(block, ensure_ascii=False))
for choice in data.get("choices") or []:
print("Choice", choice.get("index"), json.dumps(choice.get("message", choice.get("delta", {})), ensure_ascii=False))
for index, item in enumerate(data.get("output") or []):
print("Output", index, json.dumps(item, ensure_ascii=False))
if item.get("type") == "image_generation_call" and item.get("result"):
save_blob(item["result"], item.get("output_format") or "bin", "output-" + str(index))
for ci, candidate in enumerate(data.get("candidates") or []):
for pi, part in enumerate((candidate.get("content") or {}).get("parts") or []):
print("Candidate/part", ci, pi, json.dumps(part, ensure_ascii=False))
blob = part.get("inlineData") or part.get("inline_data")
if blob and blob.get("data"):
mime = blob.get("mimeType") or blob.get("mime_type")
suffix = {"image/png":"png", "image/jpeg":"jpg", "image/webp":"webp", "audio/wav":"wav", "audio/mpeg":"mp3", "video/mp4":"mp4"}.get(mime, "bin")
save_blob(blob["data"], suffix, "candidate-" + str(ci) + "-part-" + str(pi))
save_result(result.to_dict(mode="json"))
קבלה ושמירה של תוצאות
Ailoot Ultra · OpenAI Chat
json או SSE
שמירת כל התוצאות שהושלמו
שמרו כל תגובה מלאה, קובץ ומקטע תוכן שהוחזרו.
שמרו כל בחירה ואת התוכן, קריאות הכלים וההנמקה שלה. ב-SSE הרכיבו עדכונים לפי אינדקס הבחירה/הכלי ושמרו את סיבת הסיום הסופית ואת השימוש.
כשצריך לבדוק את התגובה המקורית
שמרו מזהי בקשות/תגובות וכותרות. לא מסופק URL כללי לאחזור משימת טקסט.
שדות התגובה
| שדה | סוג |
|---|---|
שדהchoices[].index | סוגinteger |
שדהchoices[].message.content | סוגstring|null |
שדהchoices[].message.tool_calls | סוגtool_call[] |
שדהchoices[].message.reasoning_content | סוגstring |
שדהchoices[].message.reasoning_details | סוגobject|array |
שדהchoices[].finish_reason | סוגstring|null |
שדהusage | סוגobject |
שגיאות והשלבים הבאים
| תגובה | תנאי | השלב הבא |
|---|---|---|
תגובה400 · invalid_request_error | תנאישדות נדרשים, ייצוג חומר או ערך פרמטר שאינם תקינים | השלב הבאתקנו את השדות שצוינו לפני בקשת יצירה חדשה. |
כינויים
כינויים למודל
Ailoot Ultra codegeex-4
כינויים לנתיבי שיטות
/chat/completions
מזהי מודלים קשורים IDs
Ailoot Ultra · Anthropic Messages POST /v1/messages codegeex-4
codegeex-4התחלה
CodeGeeX4 היא משפחת מודלי תכנות רב־לשונית ליצירת קוד, להשלמה, להסבר, לתיקון ולשאלות על מאגרי קוד. המדריכים המקוריים שלה כוללים הנחיות ייעודיות למשימה, מילוי פערים בין חלקי קוד קיימים ושימוש בקבצים קשורים להכנת שינויים עם נתיבי קבצים מפורשים.
- סוגי קלט נתמכים
- טקסט
- תוצאות
- json · sse
זמין ב-Ailoot · קלט ושיטות
Ailoot Ultra · Anthropic Messages POST /v1/messages
- סוגי קלט
text- סוגי פלט
json,sse- פורמט פלט
- JSON או SSE
| שדה | סוג | דרישה | ערכים ומגבלות | ברירת מחדל |
|---|---|---|---|---|
שדהmodel | סוגstring | דרישהחובה | ערכים ומגבלות codegeex-4 | ברירת מחדל— |
שדהmessages | סוגmessage[] | דרישהחובה | ערכים ומגבלות | ברירת מחדל— |
שדהmessages[].role | סוגstring | דרישהחובה | ערכים ומגבלות user, assistant | ברירת מחדל— |
שדהmessages[].content | סוגstring | דרישהחובה | ערכים ומגבלות | ברירת מחדל— |
שדהmax_tokens | סוגinteger | דרישהחובה | ערכים ומגבלות | ברירת מחדל— |
שדהstream | סוגboolean | דרישהרשות | ערכים ומגבלות | ברירת מחדלfalse |
שילובים של חומרי קלט
טקסט · טקסט UTF-8
מחרוזת messages[].content
פרמטרים ומחזור חיים של השיטה
| פרמטר | מפרט |
|---|---|
פרמטרcontent_type | מפרטapplication/json |
פרמטרrequired | מפרטmodel, messages, max_tokens |
פרמטרoptional_controls | מפרטstream |
פרמטרmaterial_types | מפרטtext |
פרמטרtext_file_material | מפרטקראו את מסמך UTF-8 בפועל והכניסו את הטקסט שלו לקלט שצוין או למחרוזת תוכן ההודעה. |
מחזור חיים: synchronous_or_streamed
תעריפים
מידע תעריפים אינו מוסיף אפשרויות לבקשה. הפרמטרים הנתמכים מפורטים בשיטה שנבחרה.
- מצב מהיר
- לא צוין כאשר נבחר מצב מהיר
- מצב Flex
- לא צוין כאשר נבחר מצב flex
- מאמץ חשיבה מרבי
- לא צוין כאשר מאמץ החשיבה המרבי משתמש בהתאמת ברירת המחדל (default)
תעריפי Ailoot
מחירים לפי תצורה
| תצורה | טבלת תעריפים | חיוב |
|---|---|---|
| תצורהתעריפי הבסיס לטוקנים | טבלת תעריפיםתעריף בסיס | חיוב קלט · טוקני קלט $0.028 / 1K טוקנים פלט · טוקני פלט $0.028 / 1K טוקנים קלט · קריאה מהמטמון $0 / 1K טוקנים קלט · כתיבה למטמון $0 / 1K טוקנים קלט · כתיבה למטמון, 1 שעה — / 1K טוקנים |
לפני הבקשה Ailoot משריינת סכום משוער. לאחר קבלת התוצאה היא מסדירה את החיוב הסופי לפי השימוש המדוד. הסדרת חיוב בהזרמה משתמשת ברשומת השימוש הסופית. איך פועלים שריון הסכום והסדרת החיוב →
דוגמאות לבקשות
Ailoot Ultra · Anthropic Messages
{
"model": "codegeex-4",
"max_tokens": 128,
"messages": [
{
"role": "user",
"content": "Summarize the incident report."
}
],
"stream": false
}set -eu
: "${AILOOT_API_KEY:?Set your Ailoot API key}"
: "${AILOOT_TEXT_FILE:?Set your actual UTF-8 document}"
export AILOOT_TEXT_FILE
python3 - <<'PY_REQUEST'
import json, os
from pathlib import Path
source_file = Path(os.environ['AILOOT_TEXT_FILE'])
if not source_file.is_file():
raise SystemExit('Set AILOOT_TEXT_FILE to your actual UTF-8 document')
text = source_file.read_text(encoding='utf-8')
if not text.strip():
raise SystemExit('Choose a document containing text')
payload = {'model': 'codegeex-4', 'max_tokens': 128, 'messages': [{'role': 'user', 'content': 'Summarize the incident report.'}]}
payload['messages'][0]['content'] = 'Summarize this material and quote supporting source passages.\n\n' + text
Path('request.json').write_text(json.dumps(payload, ensure_ascii=False), encoding='utf-8')
PY_REQUEST
curl --fail-with-body --silent --show-error https://api.ailoot.ai/v1/messages \
-H "x-api-key: $AILOOT_API_KEY" -H 'anthropic-version: 2023-06-01' -H 'Content-Type: application/json' \
--data-binary @request.json -D response-headers.txt -o result.json
python3 - <<'PY_RESULT'
import json
from pathlib import Path
result = json.loads(Path('result.json').read_text(encoding='utf-8'))
print(json.dumps(result, ensure_ascii=False, indent=2))
PY_RESULT
import json, os
from pathlib import Path
source_file = Path(os.environ['AILOOT_TEXT_FILE'])
if not source_file.is_file():
raise SystemExit('Set AILOOT_TEXT_FILE to your actual UTF-8 document')
text = source_file.read_text(encoding='utf-8')
if not text.strip():
raise SystemExit('Choose a document containing text')
payload = {'model': 'codegeex-4', 'max_tokens': 128, 'messages': [{'role': 'user', 'content': 'Summarize the incident report.'}]}
payload['messages'][0]['content'] = 'Summarize this material and quote supporting source passages.\n\n' + text
from urllib.request import Request, urlopen
from urllib.error import HTTPError
api_key = os.environ['AILOOT_API_KEY']
if not api_key.strip():
raise SystemExit('Set AILOOT_API_KEY before making a request')
headers = {'x-api-key': 'PLACEHOLDER_KEY', 'anthropic-version': '2023-06-01', 'Content-Type': 'application/json'}
headers['x-api-key'] = api_key
request = Request('https://api.ailoot.ai/v1/messages', data=json.dumps(payload, ensure_ascii=False).encode('utf-8'), headers=headers, method='POST')
try:
with urlopen(request, timeout=120) as response:
raw = response.read()
Path('response-headers.txt').write_text(str(response.headers), encoding='utf-8')
except HTTPError as error:
Path('result.json').write_bytes(error.read())
Path('response-headers.txt').write_text(str(error.headers), encoding='utf-8')
raise
Path('result.json').write_bytes(raw)
import json
from pathlib import Path
result = json.loads(Path('result.json').read_text(encoding='utf-8'))
print(json.dumps(result, ensure_ascii=False, indent=2))
קבלה ושמירה של תוצאות
Ailoot Ultra · Anthropic Messages
JSON או SSE
שמירת כל התוצאות שהושלמו
שמרו כל תגובה מלאה, קובץ ומקטע תוכן שהוחזרו.
שמרו את כל בלוקי התוכן, חתימות החשיבה ומזהי השימוש בכלים בפועל. הרכיבו את כל עדכוני הבלוקים של SSE; בלוק הטקסט הראשון אינו הפלט המלא.
כשצריך לבדוק את התגובה המקורית
שמרו מזהי בקשות/תגובות וכותרות. לא מסופק URL כללי לאחזור משימת טקסט.
שדות התגובה
| שדה | סוג |
|---|---|
שדהid | סוגstring |
שדהmodel | סוגstring |
שדהcontent[] | סוגtext|thinking|tool_use|other content block |
שדהstop_reason | סוגstring|null |
שדהusage | סוגobject |
שגיאות והשלבים הבאים
| תגובה | תנאי | השלב הבא |
|---|---|---|
תגובה400 · invalid_request_error | תנאישדות נדרשים, ייצוג חומר או ערך פרמטר שאינם תקינים | השלב הבאתקנו את השדות שצוינו לפני בקשת יצירה חדשה. |
כינויים
כינויים למודל
Ailoot Ultra codegeex-4
כינויים לנתיבי שיטות
/chat/completions
מזהי מודלים קשורים IDs
FAQ · CodeGeeX-4
- אילו קלטים ותוצאות זמינים?
POST /v1/chat/completions·codegeex-4:text→textPOST /v1/messages·codegeex-4:text→json,sse- באילו שדות הבקשה משתמשת?
POST /v1/chat/completions·codegeex-4:model,messages,streamPOST /v1/messages·codegeex-4:model,messages,max_tokens,stream- אילו מגבלות חלות?
POST /v1/chat/completions·codegeex-4:messages.min_items:1