Test Reasoning Serialization Validates that fields are correctly serialized into provider-specific JSON for OpenRouter, Anthropic, GitHub Copilot, and Codex. Quick Start Run all tests with the bundled script: The script builds forge in debug mode, runs each provider/model combination, captures the outgoing HTTP request body via , and asserts the correct JSON fields. Running a Single Test Manually Then inspect for the expected fields. Test Coverage | Provider | Model | Config fields | Expected JSON field | | ---------------- | ---------------------------- | ------------------------------------…

\\t' read -r type msg; do\n case \"$type\" in\n HEADER) printf \"\\n${BOLD}${CYAN}▶ %s${RESET}\\n\" \"$msg\" ;;\n PASS) printf \" ${GREEN}✓${RESET} %s\\n\" \"$msg\"; PASS=$((PASS + 1)) ;;\n FAIL) printf \" ${RED}✗${RESET} %s\\n\" \"$msg\"; FAIL=$((FAIL + 1)) ;;\n SKIP) printf \" ${YELLOW}~${RESET} %s\\n\" \"$msg\"; SKIP=$((SKIP + 1)) ;;\n esac\n done \u003c \"$f\"\ndone\n\n# ─── summary ──────────────────────────────────────────────────────────────────\n\nprintf \"\\n${BOLD}─────────────────────────────────────────${RESET}\\n\"\nprintf \"${BOLD}Results:${RESET} \"\nprintf \"${GREEN}%d passed${RESET} \" \"$PASS\"\n[ \"$FAIL\" -gt 0 ] && printf \"${RED}%d failed${RESET} \" \"$FAIL\" \\\n || printf \"${DIM}%d failed${RESET} \" \"$FAIL\"\nprintf \"${YELLOW}%d skipped${RESET}\\n\\n\" \"$SKIP\"\n\n[ \"$FAIL\" -eq 0 ]\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":19063,"content_sha256":"09d1dbbf67a3d64883db511c8a2baf109c69147d6a7fb321c313085d9bd4fc88"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Test Reasoning Serialization","type":"text"}]},{"type":"paragraph","content":[{"text":"Validates that ","type":"text"},{"text":"ReasoningConfig","type":"text","marks":[{"type":"code_inline"}]},{"text":" fields are correctly serialized into provider-specific JSON for OpenRouter, Anthropic, GitHub Copilot, and Codex.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Start","type":"text"}]},{"type":"paragraph","content":[{"text":"Run all tests with the bundled script:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"./scripts/test-reasoning.sh","type":"text"}]},{"type":"paragraph","content":[{"text":"The script builds forge in debug mode, runs each provider/model combination, captures the outgoing HTTP request body via ","type":"text"},{"text":"FORGE_DEBUG_REQUESTS","type":"text","marks":[{"type":"code_inline"}]},{"text":", and asserts the correct JSON fields.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Running a Single Test Manually","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"FORGE_DEBUG_REQUESTS=\"forge.request.json\" \\\nFORGE_SESSION__PROVIDER_ID=\u003cprovider_id> \\\nFORGE_SESSION__MODEL_ID=\u003cmodel_id> \\\nFORGE_REASONING__EFFORT=\u003ceffort> \\\ntarget/debug/forge -p \"Hello!\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Then inspect ","type":"text"},{"text":".forge/forge.request.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" for the expected fields.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Test Coverage","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Provider","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Model","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Config fields","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Expected JSON field","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai/o4-mini","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: none|minimal|low|medium|high|xhigh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.effort","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai/o4-mini","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"max_tokens: 4000","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.max_tokens","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai/o4-mini","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: high","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"exclude: true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.effort","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":".exclude","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"openai/o4-mini","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enabled: true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.enabled","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"anthropic/claude-opus-4-5","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"max_tokens: 4000","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.max_tokens","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"moonshotai/kimi-k2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"max_tokens: 4000","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.max_tokens","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"moonshotai/kimi-k2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: high","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.effort","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"minimax/minimax-m2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"max_tokens: 4000","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.max_tokens","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"open_router","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"minimax/minimax-m2","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: high","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.effort","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"anthropic","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"claude-opus-4-6","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: low|medium|high|max","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"output_config.effort","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"anthropic","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"claude-3-7-sonnet-20250219","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"enabled: true","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"max_tokens: 8000","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"thinking.type","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"budget_tokens","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"github_copilot","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"o4-mini","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: none|minimal|low|medium|high|xhigh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning_effort","type":"text","marks":[{"type":"code_inline"}]},{"text":" (top-level)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"codex","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"gpt-5.1-codex","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: none|minimal|low|medium|high|xhigh","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.effort","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":".summary","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"codex","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"gpt-5.1-codex","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: medium","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"exclude: true","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"reasoning.summary = \"concise\"","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"all providers","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"one model each","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"effort: invalid","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"non-zero exit, no request written","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Tests for unconfigured providers are skipped automatically. Invalid-effort tests run regardless of credentials — the rejection happens at config parse time before any provider interaction.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"References","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"OpenAI Reasoning guide","type":"text","marks":[{"type":"link","attrs":{"href":"https://developers.openai.com/api/docs/guides/reasoning","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"OpenAI Chat Completions API reference","type":"text","marks":[{"type":"link","attrs":{"href":"https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Anthropic Extended Thinking","type":"text","marks":[{"type":"link","attrs":{"href":"https://platform.claude.com/docs/en/build-with-claude/effort","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"OpenRouter Reasoning Tokens","type":"text","marks":[{"type":"link","attrs":{"href":"https://openrouter.ai/docs/guides/best-practices/reasoning-tokens","title":null}}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"test-reasoning","author":"@skillopedia","source":{"stars":7366,"repo_name":"forge","origin_url":"https://github.com/antinomyhq/forge/blob/HEAD/.forge/skills/test-reasoning/SKILL.md","repo_owner":"antinomyhq","body_sha256":"e648896ab32c8fc09d8fc6e05ef73a676f6eda257c0fd459518f89b73ad6aa8f","cluster_key":"7aa738cde25c99d4314d6f9dc94e7b8d53ec4436f64d39123cae6f965ea62605","clean_bundle":{"format":"clean-skill-bundle-v1","source":"antinomyhq/forge/.forge/skills/test-reasoning/SKILL.md","attachments":[{"id":"4e4e21af-3a0b-55d3-887d-4f4348ecb625","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4e4e21af-3a0b-55d3-887d-4f4348ecb625/attachment.sh","path":"scripts/test-reasoning.sh","size":19063,"sha256":"09d1dbbf67a3d64883db511c8a2baf109c69147d6a7fb321c313085d9bd4fc88","contentType":"application/x-sh; charset=utf-8"}],"bundle_sha256":"247b33b7f04ad74ebc89c746af000d6ddf053c766af64e459128c5f64aa75e90","attachment_count":1,"text_attachments":1,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":".forge/skills/test-reasoning/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"testing-qa","category_label":"Testing"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"testing-qa","import_tag":"clean-skills-v1","description":"Validate that reasoning parameters are correctly serialized and sent to provider APIs. Use when the user asks to test reasoning serialization, run reasoning tests, verify reasoning config fields, or check that ReasoningConfig maps correctly to provider-specific JSON (OpenRouter, Anthropic, GitHub Copilot, Codex)."}},"renderedAt":1782979998340}

Test Reasoning Serialization Validates that fields are correctly serialized into provider-specific JSON for OpenRouter, Anthropic, GitHub Copilot, and Codex. Quick Start Run all tests with the bundled script: The script builds forge in debug mode, runs each provider/model combination, captures the outgoing HTTP request body via , and asserts the correct JSON fields. Running a Single Test Manually Then inspect for the expected fields. Test Coverage | Provider | Model | Config fields | Expected JSON field | | ---------------- | ---------------------------- | ------------------------------------…