mirror of
https://github.com/hanzoai/opencode-openai-codex-auth.git
synced 2026-09-24 17:01:02 +00:00
This release includes comprehensive OpenAI ToS compliance updates and fixes 4 critical bugs that prevented per-model options and multi-turn conversations from working correctly. ## ๐ Compliance & Legal Updates ### Terms of Service & Usage Guidelines - Added comprehensive ToS & Usage Notice to README emphasizing personal use only - Added Rate Limits & Responsible Use section with best practices - Added extensive FAQ section addressing TOS compliance questions - Updated LICENSE with MIT + Usage Disclaimer for personal development use - Added compliance header to index.ts documenting intended use cases ### New Documentation - **CONTRIBUTING.md**: Complete contribution guidelines with compliance requirements - **SECURITY.md**: Security policy, vulnerability reporting, best practices - **docs/privacy.md**: Comprehensive privacy & data handling documentation - **Issue Templates**: Bug reports & feature requests with compliance checklists ### Documentation Updates - Updated docs/index.md with usage notice and trademark disclaimers - Updated docs/getting-started.md with "Before You Begin" compliance notice - Updated docs/troubleshooting.md with subscription & compliance sections - All references updated to "Plus/Pro" (removed Team/Enterprise mentions) ### Key Compliance Principles - โ Emphasizes personal development use with own ChatGPT Plus/Pro subscription - โ Uses OpenAI's official OAuth authentication (same as Codex CLI) - โ Clear prohibition of commercial resale, multi-user services - โ Not a "free API alternative" - uses existing ChatGPT subscription - โ Proper trademark notices and attribution to OpenAI - โ Transparent about data handling and privacy ## ๐ Critical Bug Fixes ### Bug #1: Per-Model Options Ignored (Config Lookup Mismatch) **Severity:** ๐ด HIGH Users configured different reasoning levels for each model variant, but all variants behaved identically because the plugin was looking up normalized model names instead of the original config keys. **Fix:** lib/request/request-transformer.ts:277 - Use original model name for config lookup before normalization - Allows per-model options to work correctly - Impact: Different reasoning levels now properly applied per variant ### Bug #2: Multi-Turn Conversations Fail (AI SDK Compatibility) **Severity:** ๐ด CRITICAL Multi-turn conversations failed with "Item not found" errors because: 1. AI SDK sends `item_reference` (not in Codex API spec) 2. IDs weren't completely stripped for stateless mode (store: false) **Fix:** lib/request/request-transformer.ts:114-135 - Filter out AI SDK `item_reference` items - Strip ALL IDs from remaining items (not just rs_* prefix) - Confirmed ChatGPT backend requires store: false via testing - Full message history preserved for LLM context ### Bug #3: Case-Sensitive Normalization **Severity:** ๐ก MEDIUM **Fix:** lib/request/request-transformer.ts:22-27 - Added toLowerCase() for case-insensitive matching - Backwards compatible with old verbose config names - Handles uppercase/mixed case user input ### Bug #4: GitHub API Rate Limiting **Severity:** ๐ก MEDIUM Plugin checked GitHub on every request, exhausting 60 req/hour limit. 15-minute cache timestamp was stored but never checked. **Fix:** lib/prompts/codex.ts:50-53, lib/prompts/opencode-codex.ts:47-50 - Check cache TTL before GitHub API call - Only fetch if cache >15min old - Prevents rate limit exhaustion during testing ## โจ Enhancements ### Debug Logging System - New environment variable: `DEBUG_CODEX_PLUGIN=1` - Added logDebug() and logWarn() functions - Shows config lookups, ID filtering, options resolution - File: lib/logger.ts ### Optimized Config Structure - Changed to Codex CLI preset names (gpt-5-codex-low, etc.) - Removed redundant `id` field (not used by OpenAI provider) - Added `name` field for friendly TUI display - File: config/full-opencode.json ### GitHub Pages Documentation - Complete documentation restructure for GitHub Pages - User guides: getting-started.md, configuration.md, troubleshooting.md - Developer guides: ARCHITECTURE.md, CONFIG_FLOW.md, CONFIG_FIELDS.md, TESTING.md - Privacy policy, security policy, contribution guidelines ## ๐งช Testing ### Test Coverage - โ 159 unit tests passing (30+ new tests) - โ 14 integration tests passing (actual API verification) - โ All documented scenarios have test coverage ### Integration Tests (scripts/test-all-models.sh) - Tests all 9 custom model configurations - Tests all 4 default OpenCode models - Verifies backwards compatibility with old config format - Uses ENABLE_PLUGIN_REQUEST_LOGGING to verify actual API requests ### Test Results - 14/14 model configuration tests passing - All per-model options verified correct - Multi-turn conversations work without errors - Backwards compatibility confirmed ## ๐ Files Changed ### Modified (7 files) - lib/request/request-transformer.ts: Config lookup & ID filtering fixes - lib/prompts/codex.ts: 15-minute cache TTL - lib/prompts/opencode-codex.ts: 15-minute cache TTL - lib/logger.ts: Debug logging system - config/full-opencode.json: Optimized structure - test/request-transformer.test.ts: 30+ new tests - LICENSE: Added usage disclaimer - index.ts: Added compliance header - README.md: Added ToS, Rate Limits, FAQ sections ### Created (20+ files) - CONTRIBUTING.md: Contribution guidelines - SECURITY.md: Security policy - docs/index.md: GitHub Pages landing - docs/getting-started.md: Installation guide - docs/configuration.md: Advanced config - docs/troubleshooting.md: Debug guide - docs/privacy.md: Privacy policy - docs/development/ARCHITECTURE.md: Technical architecture - docs/development/CONFIG_FLOW.md: Config system internals - docs/development/CONFIG_FIELDS.md: Field usage guide - docs/development/TESTING.md: Testing guide - .github/ISSUE_TEMPLATE/bug_report.md - .github/ISSUE_TEMPLATE/feature_request.md - .github/ISSUE_TEMPLATE/config.yml - scripts/test-all-models.sh: Automated testing ## ๐ฏ Verification All scenarios tested and verified: - โ Default models work without config - โ Custom models with per-variant options - โ Old config format (backwards compatible) - โ Mixed default + custom models - โ Multi-turn conversations (no "item not found" errors) - โ Model switching with different options - โ All normalization patterns - โ Complete ID filtering ## ๐ Documentation Complete documentation suite (100+ KB): - User guides for installation, configuration, troubleshooting - Developer guides for architecture, config system, testing - Privacy policy and security policy - Compliance guidelines and contribution requirements - Release notes in tmp/release-notes/ ## ๐ References - OpenAI Terms of Use: https://openai.com/policies/terms-of-use/ - OpenAI Usage Policies: https://openai.com/policies/usage-policies/ - OpenAI Platform API: https://platform.openai.com/ - OpenAI Codex CLI: https://github.com/openai/codex Co-authored-by: Hanzo Dev <[email protected]>
192 lines
6.2 KiB
TypeScript
192 lines
6.2 KiB
TypeScript
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
import { join, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { homedir } from "node:os";
|
|
import type { GitHubRelease, CacheMetadata } from "../types.js";
|
|
|
|
// Codex instructions constants
|
|
const GITHUB_API_RELEASES = "https://api.github.com/repos/openai/codex/releases/latest";
|
|
const CACHE_DIR = join(homedir(), ".opencode", "cache");
|
|
const CACHE_FILE = join(CACHE_DIR, "codex-instructions.md");
|
|
const CACHE_METADATA_FILE = join(CACHE_DIR, "codex-instructions-meta.json");
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
/**
|
|
* Get the latest release tag from GitHub
|
|
* @returns Release tag name (e.g., "rust-v0.43.0")
|
|
*/
|
|
async function getLatestReleaseTag(): Promise<string> {
|
|
const response = await fetch(GITHUB_API_RELEASES);
|
|
if (!response.ok) throw new Error(`Failed to fetch latest release: ${response.status}`);
|
|
const data = (await response.json()) as GitHubRelease;
|
|
return data.tag_name;
|
|
}
|
|
|
|
/**
|
|
* Fetch Codex instructions from GitHub with ETag-based caching
|
|
* Uses HTTP conditional requests to efficiently check for updates
|
|
* Always fetches from the latest release tag, not main branch
|
|
*
|
|
* Rate limit protection: Only checks GitHub if cache is older than 15 minutes
|
|
* @returns Codex instructions
|
|
*/
|
|
export async function getCodexInstructions(): Promise<string> {
|
|
try {
|
|
// Load cached metadata (includes ETag, tag, and lastChecked timestamp)
|
|
let cachedETag: string | null = null;
|
|
let cachedTag: string | null = null;
|
|
let cachedTimestamp: number | null = null;
|
|
|
|
if (existsSync(CACHE_METADATA_FILE)) {
|
|
const metadata = JSON.parse(readFileSync(CACHE_METADATA_FILE, "utf8")) as CacheMetadata;
|
|
cachedETag = metadata.etag;
|
|
cachedTag = metadata.tag;
|
|
cachedTimestamp = metadata.lastChecked;
|
|
}
|
|
|
|
// Rate limit protection: If cache is less than 15 minutes old, use it
|
|
const CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes
|
|
if (cachedTimestamp && (Date.now() - cachedTimestamp) < CACHE_TTL_MS && existsSync(CACHE_FILE)) {
|
|
return readFileSync(CACHE_FILE, "utf8");
|
|
}
|
|
|
|
// Get the latest release tag (only if cache is stale or missing)
|
|
const latestTag = await getLatestReleaseTag();
|
|
const CODEX_INSTRUCTIONS_URL = `https://raw.githubusercontent.com/openai/codex/${latestTag}/codex-rs/core/gpt_5_codex_prompt.md`;
|
|
|
|
// If tag changed, we need to fetch new instructions
|
|
if (cachedTag !== latestTag) {
|
|
cachedETag = null; // Force re-fetch
|
|
}
|
|
|
|
// Make conditional request with If-None-Match header
|
|
const headers: Record<string, string> = {};
|
|
if (cachedETag) {
|
|
headers["If-None-Match"] = cachedETag;
|
|
}
|
|
|
|
const response = await fetch(CODEX_INSTRUCTIONS_URL, { headers });
|
|
|
|
// 304 Not Modified - our cached version is still current
|
|
if (response.status === 304) {
|
|
if (existsSync(CACHE_FILE)) {
|
|
return readFileSync(CACHE_FILE, "utf8");
|
|
}
|
|
// Cache file missing but GitHub says not modified - fall through to re-fetch
|
|
}
|
|
|
|
// 200 OK - new content or first fetch
|
|
if (response.ok) {
|
|
const instructions = await response.text();
|
|
const newETag = response.headers.get("etag");
|
|
|
|
// Create cache directory if it doesn't exist
|
|
if (!existsSync(CACHE_DIR)) {
|
|
mkdirSync(CACHE_DIR, { recursive: true });
|
|
}
|
|
|
|
// Cache the instructions with ETag and tag (verbatim from GitHub)
|
|
writeFileSync(CACHE_FILE, instructions, "utf8");
|
|
writeFileSync(
|
|
CACHE_METADATA_FILE,
|
|
JSON.stringify({
|
|
etag: newETag,
|
|
tag: latestTag,
|
|
lastChecked: Date.now(),
|
|
url: CODEX_INSTRUCTIONS_URL,
|
|
} satisfies CacheMetadata),
|
|
"utf8",
|
|
);
|
|
|
|
return instructions;
|
|
}
|
|
|
|
throw new Error(`HTTP ${response.status}`);
|
|
} catch (error) {
|
|
const err = error as Error;
|
|
console.error(
|
|
"[openai-codex-plugin] Failed to fetch instructions from GitHub:",
|
|
err.message,
|
|
);
|
|
|
|
// Try to use cached version even if stale
|
|
if (existsSync(CACHE_FILE)) {
|
|
console.error("[openai-codex-plugin] Using cached instructions");
|
|
return readFileSync(CACHE_FILE, "utf8");
|
|
}
|
|
|
|
// Fall back to bundled version
|
|
console.error("[openai-codex-plugin] Falling back to bundled instructions");
|
|
return readFileSync(join(__dirname, "codex-instructions.md"), "utf8");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tool remapping instructions for opencode tools
|
|
*/
|
|
export const TOOL_REMAP_MESSAGE = `<user_instructions priority="0">
|
|
<environment_override priority="0">
|
|
YOU ARE IN A DIFFERENT ENVIRONMENT. These instructions override ALL previous tool references.
|
|
</environment_override>
|
|
|
|
<tool_replacements priority="0">
|
|
<critical_rule priority="0">
|
|
โ APPLY_PATCH DOES NOT EXIST โ โ
USE "edit" INSTEAD
|
|
- NEVER use: apply_patch, applyPatch
|
|
- ALWAYS use: edit tool for ALL file modifications
|
|
- Before modifying files: Verify you're using "edit", NOT "apply_patch"
|
|
</critical_rule>
|
|
|
|
<critical_rule priority="0">
|
|
โ UPDATE_PLAN DOES NOT EXIST โ โ
USE "todowrite" INSTEAD
|
|
- NEVER use: update_plan, updatePlan
|
|
- ALWAYS use: todowrite for ALL task/plan operations
|
|
- Use todoread to read current plan
|
|
- Before plan operations: Verify you're using "todowrite", NOT "update_plan"
|
|
</critical_rule>
|
|
</tool_replacements>
|
|
|
|
<available_tools priority="0">
|
|
File Operations:
|
|
โข write - Create new files
|
|
โข edit - Modify existing files (REPLACES apply_patch)
|
|
โข patch - Apply diff patches
|
|
โข read - Read file contents
|
|
|
|
Search/Discovery:
|
|
โข grep - Search file contents
|
|
โข glob - Find files by pattern
|
|
โข list - List directories (use relative paths)
|
|
|
|
Execution:
|
|
โข bash - Run shell commands
|
|
|
|
Network:
|
|
โข webfetch - Fetch web content
|
|
|
|
Task Management:
|
|
โข todowrite - Manage tasks/plans (REPLACES update_plan)
|
|
โข todoread - Read current plan
|
|
</available_tools>
|
|
|
|
<substitution_rules priority="0">
|
|
Base instruction says: You MUST use instead:
|
|
apply_patch โ edit
|
|
update_plan โ todowrite
|
|
read_plan โ todoread
|
|
absolute paths โ relative paths
|
|
</substitution_rules>
|
|
|
|
<verification_checklist priority="0">
|
|
Before file/plan modifications:
|
|
1. Am I using "edit" NOT "apply_patch"?
|
|
2. Am I using "todowrite" NOT "update_plan"?
|
|
3. Is this tool in the approved list above?
|
|
4. Am I using relative paths?
|
|
|
|
If ANY answer is NO โ STOP and correct before proceeding.
|
|
</verification_checklist>
|
|
</user_instructions>`;
|