کدکس در نسخه‌ی ۰٫۱۵۴ دو کار را اضافه کرد که مستقیماً روی هزینه و سرعت کار شما اثر می‌گذارند: دو سطح تازه‌ی تلاش استدلال به‌نام max و ultra، و چک‌اوت جدا برای هر نشست. تلاش استدلال را با مقایسه‌ی چرخ نسخه‌ها ثابت کردم: نسخه‌ی پیشین ۰٫۱۴۷ شش سطح داشت و ۰٫۱۵۴ هشت سطح. چک‌اوت آزمایشی است و پرچمش بدون فعال کردن یک ویژگی خطا می‌دهد. هر دو را روی کدکس نصب‌شده‌ی ۰٫۱۵۴ اجرا کردم و سه ناسازگاری واقعی پیدا شد.

این دو ویژگی در ظاهر جدا از هم‌اند و هر دو به یک سؤال برمی‌گردند: چقدر از کار را به یک نشست می‌دهید و آن نشست کجا کار می‌کند. سطح استدلال تعیین می‌کند نشست چقدر فکر کند، و چک‌اوت جدا تعیین می‌کند نشست کدام شاخه از مخزن را می‌بیند. اولی روی هزینه اثر دارد و دومی روی ایمنی، و ترکیبشان بیشتر از جمعشان ارزش دارد.

دو سطح تازه، و اینکه واقعاً در کدام نسخه آمدند

ادعای رایج این است که هر هشت سطح تلاش استدلال از قبل وجود داشتند و کدکس فقط نامشان را عوض کرده. برای بررسی، سه چرخ پیاپی را از رجیستری گرفتم و فهرست اعضای یک شمارشی را از درون خود بسته خواندم. نتیجه روشن است.

<span class="code-comment"># effort_diff.py -- مقایسه‌ی عضوهای ReasoningEffort بین سه نسخه</span>
import io, json, re, urllib.request, zipfile

def members(src: str) -> list[str]:
    m = re.search(r"class ReasoningEffort\(str, Enum\):(.*?)\n\n", src, re.S)
    return re.findall(r'^\s{4}(\w+) = "([\w-]+)"', m.group(1), re.M)

info = json.load(urllib.request.urlopen(
    "https://pypi.org/pypi/openai-codex/json"))

for v in ("0.147.0", "0.154.0", "0.157.1"):
    f = next(w for w in info["releases"][v]
             if w["filename"].endswith("py3-none-any.whl"))
    data = urllib.request.urlopen(f["url"]).read()
    src = zipfile.ZipFile(io.BytesIO(data)).read(
        "openai_codex/generated/v2_all.py").decode()
    print(v, [m[0] for m in members(src)])

خروجی نشان می‌دهد نسخه‌ی ۰٫۱۴۷ شش عضو داشت و نسخه‌ی ۰٫۱۵۴ هشت عضو. دو عضو تازه دقیقاً همان max و ultra هستند که در یادداشت انتشار به آن‌ها اشاره شده است. نسخه‌ی ۰٫۱۵۷ هم همان هشت عضو را نگه داشته است، پس این یک تغییر افزایشی بوده و نه یک بازنویسی. برای دیدن همین فهرست از سمت انتشار، تاریخچه‌ی تغییرات را کنار مخزن باز کنید؛ مستند app-server هم نشان می‌دهد این سطوح از چه لایه‌ای خوانده می‌شوند.

نسخهاعضاتعداد
۰٫۱۴۷٫۰none تا xhigh۶
۰٫۱۵۴٫۰none تا ultra۸
۰٫۱۵۷٫۱none تا ultra۸

اما یک نکته‌ی ایمنی دارد که در نوشته‌های معمول دیده نمی‌شود. این شمارشی یک متد به‌نام _missing_ دارد که هر رشته‌ی ناشناخته‌ای را می‌پذیرد و آن را عضوی از همان شمارشی می‌کند. یعنی نوشتن یک مقدار نامعتبر خطا نمی‌دهد؛ بی‌صدا رد می‌شود و بعداً سرور تصمیم می‌گیرد چه کند.

<span class="code-comment"># نامعتبر بی‌صدا رد می‌شود -- این یک آزمون منفی واقعی است</span>
>>> [m.value for m in ReasoningEffort]
['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra']

>>> ReasoningEffort('ultra').value
'ultra'
>>> ReasoningEffort('turbo').value
'turbo'          <-- پذیرفته شد، چون _missing_ این کار را می‌کند

پس « ultra تایپ نادرست را می‌پذیرد» یعنی شما یک تایپ‌چک زمان اجرا ندارید و خطا را از سرور می‌گیرید، آن هم به شکل پیامی که ربطی به تایپ ندارد. اگر مقدار تلاش استدلال را از یک تنظیم بیرونی می‌خوانید، خودتان اعتبارسنجی کنید.

سطح تازه فقط در شمارشی وجود ندارد. فهرست مدل کدکس برای هر مدل، سطوح پشتیبانی‌شده و توضیح هرکدام را جدا اعلام می‌کند، و تفاوت این دو سطح تازه از همین‌جا معلوم می‌شود.

<span class="code-comment"># کدکس فهرست مدل را به‌صورت خام نشان می‌دهد</span>
$ codex debug models | python3 -c "
import json,sys
m = json.load(sys.stdin)['models'][0]
print('default:', m['default_reasoning_level'])
for lv in m['supported_reasoning_levels']:
    print(f\"  {lv['effort']:7} {lv['description']}\")
"
سطحتوضیح رسمیکاربرد
lowاستدلال سبک، پاسخ سریعپیش‌فرض مدل
highعمق بیشتر برای مسئله‌های پیچیدهکار روزمره
xhighعمق بسیار زیادمسئله‌ی سخت
maxبیشینه‌ی عمق برای سخت‌ترین مسئله‌هادیباگ واقعی
ultraبیشینه‌ی استدلال با واگذاری خودکار کارکار بلند و پرهزینه

سطح پیش‌فرض مدل low است، نه medium و نه high. اگر تا امروز بدون تنظیم کار کرده‌اید، روی سبک‌ترین حالت بوده‌اید. و توضیح ultra یک چیز مهم دارد: واگذاری خودکار کار، یعنی این سطح فقط عمق استدلال نیست، بلکه اجازه می‌دهد کار به زیرکارهای جدا تقسیم شود. این یعنی هزینه‌ی یک درخواست می‌تواند چند درخواست شود.

برای همین توصیه‌ی عملی ساده است: برای کار روزمره low یا medium کافی است، و رفتن به max را وقتی انجام دهید که یک بار با medium جواب نداده و می‌دانید چرا. ultra را برای کاری نگه دارید که ارزشش را دارد، چون هزینه‌ی آن فقط یک ضریب نیست و ساختار کار را هم عوض می‌کند.

چک‌اوت جدا: هر نشست روی شاخه‌ی خودش

بخش دوم یادداشت انتشار درباره‌ی چک‌اوت مدیریت‌شده است: نشست‌های تازه یا fork شده می‌توانند چک‌اوت جدا داشته باشند. کاربردش روشن است. به‌جای اینکه سه ایجنت روی یک شاخه بنویسند و با هم تضاد بخورند، هرکدام روی یک چک‌اوت جدا کار می‌کنند و بعد تصمیم می‌گیرید کدام ادغام شود.

پرچم در راهنمای خط فرمان وجود دارد، اما در وضعیت آزمایشی. ویژگی به‌طور پیش‌فرض خاموش است، و این را نه از یادداشت انتشار که از خود فهرست پرچم‌ها خواندم.

<span class="code-comment"># وضعیت واقعی ویژگی، از خود ابزار</span>
$ codex features list | grep worktrees
worktrees    experimental    false

$ codex features list | grep -E "multi_agent|worktree"
multi_agent             stable             true
multi_agent_v2          stable             false
use_agent_identity      under development   false
worktrees               experimental       false

پس سه واقعیت را باید کنار هم گذاشت: ویژگی آزمایشی است، به‌طور پیش‌فرض خاموش است، و برای نشست غیرتعاملی هم اضافه شده. اگر هر سه را ندانید، به خطایی می‌خورید که دلیلش را در متن خطا نوشته‌اند.

<span class="code-comment"># بدون فعال کردن ویژگی، پرچم شناخته نمی‌شود</span>
$ codex exec --worktree "این را انجام بده"
Error: --worktree requires the worktrees feature; enable it with --enable worktrees

$ codex exec --enable worktrees --worktree "این را انجام بده"
Reading additional input from stdin...
OpenAI Codex v0.154.0
--------
workdir: /root/.cxprobe/worktrees/4a8a/probe-repo
model: gpt-6-astra
provider: openai
approval: never
sandbox: workspace-write [workdir, /tmp, $TMPDIR]
reasoning effort: none
--------
hi

تفاوت مهم این است که چک‌اوت داخل خانه‌ی کدکس ساخته می‌شود، نه هرجایی در سامانه. مسیر بالا زیر پوشه‌ی چک‌اوت‌های کدکس است و نه در شاخه‌ی کاری من. وقتی git را پرسیدم، هر دو را در فهرست چک‌اوت‌ها دید و چک‌اوت تازه را در حالت سر جدا نشان داد.

<span class="code-comment"># گیت هر دو مسیر را می‌بیند؛ چک‌اوت تازه سرِ جدا دارد</span>
$ git worktree list
/root/probe-repo                          73405ae [master]
/root/.cxprobe/worktrees/4a8a/probe-repo  73405ae (detached HEAD)

سه تفاوت را کنار هم بگذارید که تصمیم شما را می‌سازند:

  • مسیر ساخت: چک‌اوت مدیریت‌شده زیر خانه‌ی کدکس ساخته می‌شود و چک‌اوت دستی هرجا که خودتان تعیین کنید.
  • نام شاخه: نام تصادفی در برابر نامی که خودتان می‌دهید و در گیت می‌ماند.
  • سر جدا: چک‌اوت مدیریت‌شده در حالت سر جدا باز می‌شود، پس شاخه‌ی اصلی شما دست‌نخورده می‌ماند.

این را با چک‌اوت دستی مقایسه کنید. چک‌اوت دستی را خودتان با دستور گیت می‌سازید و هر جا بخواهید، و نام شاخه را خودتان تعیین می‌کنید. چک‌اوت مدیریت‌شده نام تصادفی می‌سازد و مسیرش زیر خانه‌ی کدکس است. برای کار خودکار این یک امتیاز است، چون پاک‌سازی خودکار می‌شود؛ برای کار دستی یک مانع است، چون باید بدانید کجا دنبالش بگردید.

سه ناسازگاری که در عمل به آن‌ها خوردیم

ویژگی‌های آزمایشی معمولاً یک چیز را اعلام نمی‌کنند: کدام ترکیب‌ها مجاز نیست. هر سه مورد زیر را در اجرای واقعی دیدم، و هر سه از ترکیب دو پرچم می‌آمدند.

نخست، چک‌اوت و نشست گذرا با هم نمی‌شوند. نشست گذرا یعنی هیچ فایلی روی دیسک نوشته نشود، که با ساختن یک چک‌اوت تناقض دارد.

<span class="code-comment"># این ترکیب رد می‌شود، و پیام خطا دقیق است</span>
$ codex exec --worktree --ephemeral "hi"
Error: --worktree cannot be combined with --ephemeral

دوم، سطح تلاش استدلال در راهنمای خط فرمان نیست. هیچ پرچام مستقیمی برای آن وجود ندارد، چون هر مدل مجموعه‌ی سطوح خودش را جدا اعلام می‌کند. راه درست، تنظیم پیکربندی است.

<span class="code-comment"># مقدار ناشناخا را پذیرفته و در سربرگ نشان داده است</span>
$ codex exec -c model_reasoning_effort='"max"' "hi"     | grep effort
reasoning effort: max
$ codex exec -c model_reasoning_effort='"ultra"' "hi"   | grep effort
reasoning effort: ultra
$ codex exec -c model_reasoning_effort='"turbo"' "hi"   | grep effort
reasoning effort: turbo

سوم، حالت سخت‌گیرانه تنظیمات یک دروازه‌ی واقعی است. کلیدی که در این نسخه نمی‌شناسد، اجرا را متوقف می‌کند پیش از آنکه چیزی بفرستد. این همان چیزی است که برای خط لوله‌ی ساخت به درد می‌خورد و در نوشته‌ی کدکس در خط لوله به آن برمی‌گردم.

<span class="code-comment"># کلید ناشناخا پیش از هر درخواستی رد می‌شود</span>
$ codex --strict-config -c bogus_key_xyz=1 exec "hi"
Error loading config.toml: unknown configuration field `bogus_key_xyz` in -c/--config override

کدام را با چه ترتیبی

جمع‌بندی را روی ترتیب نگه دارید، چون ترتیب در اینجا مهم است. اول، پرچم‌ها را از فهرست راهنما بخوانید نه از یادداشت انتشار، چون یادداشت ممکن است پرچمی را نام ببرد که به یک ویژگی آزمایشی گره خورده است؛ همان اتفاقی که برای سرور داخلی MCP افتاد و در پست حذف زیرفرمان mcp-server دنبال شده است. دوم، قبل از هر کار خودکار، حالت سخت‌گیرانه را روشن کنید تا کلید اشتباه همان اول خطا بدهد. سوم، سطح استدلال را برای کار روزمره دست‌نخورده بگذارید و فقط برای مسئله‌ی واقعاً سخت بالا ببرید.

درباره‌ی چک‌اوت، تصمیم بستگی به این دارد که کار شما دستی است یا خودکار. اگر یک نشست را دستی می‌بینید و می‌خواهید بدانید تغییرات کجا رفت، چک‌اوت دستی بهتر است چون مسیرش را خودتان انتخاب می‌کنید. اگر چند ایجنت را موازی اجرا می‌کنید و نمی‌خواهید در مسیر پاک‌سازی به آن‌ها بگویید، چک‌اوت مدیریت‌شده کار را جمع می‌کند و به‌درد می‌خورد.

یک هشدار در پایان. هر دو ویژگی در وضعیت پیش‌نویس‌اند. max و ultra روی فهرست اعضا اضافه شده‌اند اما یادداشت انتشار تنها یک سطر درباره‌ی ثبت تغییرات تلاش استدلال در تاریخچه دارد، و چک‌اوت صراحتاً آزمایشی و خاموش است. یعنی ممکن است رفتاری که امروز می‌بینید در نسخه‌ی بعد عوض شود؛ هشدار منسوخ‌شدن یک زیرفرمان و سپس حذف کامل همان زیرفرمان دو نمونه‌ی واقعی از همین چرخه‌اند، و تاریخچه‌ی تغییرات جایی است که این حذف‌ها را پیش از وقوع اعلام می‌کند. اگر هزینه‌ی خطا برایتان گران است، مقدار تلاش استدلال را در پیکربندی پروژه بگذارید نه در فرمان، تا تغییرش یک تغییر کوچک و بازبینی‌پذیر باشد.

منابع

  1. یادداشت انتشار ۰٫۱۵۴٫۰ — نسخه‌ای که هر دو ویژگی از آن خوانده شد
  2. انتشار ۰٫۱۵۳٫۴ — آخرین نسخه‌ی پیش از آن
  3. انتشار ۰٫۱۵۵٫۰
  4. انتشار ۰٫۱۵۶٫۰
  5. انتشار ۰٫۱۵۷٫۱ — نسخه‌ای که هشت عضو را نگه داشت
  6. تاریخچه‌ی تغییرات — اعلام پیش از وقوع
  7. راهنمای app-server
  8. مستند app-server در مخزن رسمی
  9. راهنمای سرور MCP کدکس — نمونه‌ی عینی یک زیرفرمان منسوخ
  10. درخواست ادغام ۳۹۶۵۷ — هشدار منسوخ‌شدن
  11. درخواست ادغام ۴۲۹۹۳ — حذف کامل همان زیرفرمان