diff --git a/.codex/databricks-models.json b/.codex/databricks-models.json new file mode 100644 index 0000000..29a90bb --- /dev/null +++ b/.codex/databricks-models.json @@ -0,0 +1,139 @@ +{ + "models": [ + { + "slug": "databricks-gpt-5-5", + "display_name": "Databricks GPT-5.5", + "description": "GPT-5.5 hosted through Databricks AI Gateway", + "default_reasoning_level": "medium", + "supported_reasoning_levels": [ + { "effort": "low", "description": "Fast responses with lighter reasoning" }, + { "effort": "medium", "description": "Balanced speed and reasoning depth" }, + { "effort": "high", "description": "Greater reasoning depth for complex tasks" }, + { "effort": "xhigh", "description": "Maximum reasoning depth for complex tasks" } + ], + "shell_type": "default", + "visibility": "list", + "supported_in_api": true, + "priority": 100, + "additional_speed_tiers": [], + "availability_nux": null, + "upgrade": null, + "base_instructions": "", + "supports_reasoning_summaries": true, + "support_verbosity": true, + "default_verbosity": null, + "apply_patch_tool_type": null, + "truncation_policy": { "mode": "tokens", "limit": 200000 }, + "supports_parallel_tool_calls": true, + "experimental_supported_tools": [] + }, + { + "slug": "databricks-gpt-5-4", + "display_name": "Databricks GPT-5.4", + "description": "GPT-5.4 hosted through Databricks AI Gateway", + "default_reasoning_level": "medium", + "supported_reasoning_levels": [ + { "effort": "low", "description": "Fast responses with lighter reasoning" }, + { "effort": "medium", "description": "Balanced speed and reasoning depth" }, + { "effort": "high", "description": "Greater reasoning depth for complex tasks" }, + { "effort": "xhigh", "description": "Maximum reasoning depth for complex tasks" } + ], + "shell_type": "default", + "visibility": "list", + "supported_in_api": true, + "priority": 90, + "additional_speed_tiers": [], + "availability_nux": null, + "upgrade": null, + "base_instructions": "", + "supports_reasoning_summaries": true, + "support_verbosity": true, + "default_verbosity": null, + "apply_patch_tool_type": null, + "truncation_policy": { "mode": "tokens", "limit": 200000 }, + "supports_parallel_tool_calls": true, + "experimental_supported_tools": [] + }, + { + "slug": "databricks-gpt-5-4-mini", + "display_name": "Databricks GPT-5.4 Mini", + "description": "GPT-5.4 Mini hosted through Databricks AI Gateway", + "default_reasoning_level": "medium", + "supported_reasoning_levels": [ + { "effort": "low", "description": "Fast responses with lighter reasoning" }, + { "effort": "medium", "description": "Balanced speed and reasoning depth" }, + { "effort": "high", "description": "Greater reasoning depth for complex tasks" }, + { "effort": "xhigh", "description": "Maximum reasoning depth for complex tasks" } + ], + "shell_type": "default", + "visibility": "list", + "supported_in_api": true, + "priority": 80, + "additional_speed_tiers": [], + "availability_nux": null, + "upgrade": null, + "base_instructions": "", + "supports_reasoning_summaries": true, + "support_verbosity": true, + "default_verbosity": null, + "apply_patch_tool_type": null, + "truncation_policy": { "mode": "tokens", "limit": 200000 }, + "supports_parallel_tool_calls": true, + "experimental_supported_tools": [] + }, + { + "slug": "databricks-gpt-5-3-codex", + "display_name": "Databricks GPT-5.3 Codex", + "description": "GPT-5.3 Codex hosted through Databricks AI Gateway", + "default_reasoning_level": "medium", + "supported_reasoning_levels": [ + { "effort": "low", "description": "Fast responses with lighter reasoning" }, + { "effort": "medium", "description": "Balanced speed and reasoning depth" }, + { "effort": "high", "description": "Greater reasoning depth for complex tasks" }, + { "effort": "xhigh", "description": "Maximum reasoning depth for complex tasks" } + ], + "shell_type": "default", + "visibility": "list", + "supported_in_api": true, + "priority": 70, + "additional_speed_tiers": [], + "availability_nux": null, + "upgrade": null, + "base_instructions": "", + "supports_reasoning_summaries": true, + "support_verbosity": true, + "default_verbosity": null, + "apply_patch_tool_type": null, + "truncation_policy": { "mode": "tokens", "limit": 200000 }, + "supports_parallel_tool_calls": true, + "experimental_supported_tools": [] + }, + { + "slug": "databricks-gpt-5-2", + "display_name": "Databricks GPT-5.2", + "description": "GPT-5.2 hosted through Databricks AI Gateway", + "default_reasoning_level": "medium", + "supported_reasoning_levels": [ + { "effort": "low", "description": "Fast responses with lighter reasoning" }, + { "effort": "medium", "description": "Balanced speed and reasoning depth" }, + { "effort": "high", "description": "Greater reasoning depth for complex tasks" }, + { "effort": "xhigh", "description": "Maximum reasoning depth for complex tasks" } + ], + "shell_type": "default", + "visibility": "list", + "supported_in_api": true, + "priority": 60, + "additional_speed_tiers": [], + "availability_nux": null, + "upgrade": null, + "base_instructions": "", + "supports_reasoning_summaries": true, + "support_verbosity": true, + "default_verbosity": null, + "apply_patch_tool_type": null, + "truncation_policy": { "mode": "tokens", "limit": 200000 }, + "supports_parallel_tool_calls": true, + "experimental_supported_tools": [] + } + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index f9acd43..4089448 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,10 @@ uploads/ # uv lockfile — not portable across PyPI proxies, generate locally with `uv lock` uv.lock + +# Codex CLI generated/cached files (only the bundled model catalog is tracked) +.codex/* +!.codex/databricks-models.json + +# Codex skills are generated at runtime by setup_codex.py from .claude/skills/ +.agents/ diff --git a/README.md b/README.md index 55107ce..fd492bd 100644 --- a/README.md +++ b/README.md @@ -284,8 +284,8 @@ This template repo opens that vision up for every Databricks user — no IDE set |----------|----------|-------------| | `DATABRICKS_TOKEN` | No | Optional. If not set, the app prompts for a token on first session. Auto-rotated every 10 minutes | | `HOME` | Yes | Set to `/app/python/source_code` in app.yaml | -| `ANTHROPIC_MODEL` | No | Claude model name (default: `databricks-claude-opus-4-6`) | -| `CODEX_MODEL` | No | Codex model name (default: `databricks-gpt-5-3-codex`) | +| `ANTHROPIC_MODEL` | No | Claude model name (default: `databricks-claude-opus-4-7`) | +| `CODEX_MODEL` | No | Codex model name (default: `databricks-gpt-5-5`) | | `GEMINI_MODEL` | No | Gemini model name (default: `databricks-gemini-2-5-pro`) | | `DATABRICKS_GATEWAY_HOST` | No | AI Gateway URL override. Auto-discovered from `DATABRICKS_WORKSPACE_ID` if unset | diff --git a/app.py b/app.py index 46e35b6..f3e6797 100644 --- a/app.py +++ b/app.py @@ -295,10 +295,10 @@ def _configure_all_cli_auth(token): settings = { "env": { - "ANTHROPIC_MODEL": os.environ.get("ANTHROPIC_MODEL", "databricks-claude-opus-4-6"), + "ANTHROPIC_MODEL": os.environ.get("ANTHROPIC_MODEL", "databricks-claude-opus-4-7"), "ANTHROPIC_BASE_URL": anthropic_base_url, "ANTHROPIC_AUTH_TOKEN": token, - "ANTHROPIC_DEFAULT_OPUS_MODEL": "databricks-claude-opus-4-6", + "ANTHROPIC_DEFAULT_OPUS_MODEL": "databricks-claude-opus-4-7", "ANTHROPIC_DEFAULT_SONNET_MODEL": "databricks-claude-sonnet-4-6", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "databricks-claude-haiku-4-5", "ANTHROPIC_CUSTOM_HEADERS": "x-databricks-use-coding-agent-mode: true", diff --git a/app.yaml b/app.yaml index c01aa14..a0f443c 100644 --- a/app.yaml +++ b/app.yaml @@ -9,7 +9,7 @@ env: - name: GEMINI_MODEL value: databricks-gemini-2-5-pro - name: CODEX_MODEL - value: databricks-gpt-5-3-codex + value: databricks-gpt-5-5 - name: CLAUDE_CODE_DISABLE_AUTO_MEMORY value: 0 - name: MAX_CONCURRENT_SESSIONS diff --git a/docs/deployment.md b/docs/deployment.md index f948863..07c3dd6 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -67,8 +67,8 @@ databricks apps deploy \ |----------|----------|-------------| | `DATABRICKS_TOKEN` | No | Optional. If not set, the app prompts for a token on first session. Auto-rotated every 10 minutes | | `HOME` | Yes | Set to `/app/python/source_code` in app.yaml | -| `ANTHROPIC_MODEL` | No | Claude model name (default: `databricks-claude-opus-4-6`) | -| `CODEX_MODEL` | No | Codex model name (default: `databricks-gpt-5-3-codex`) | +| `ANTHROPIC_MODEL` | No | Claude model name (default: `databricks-claude-opus-4-7`) | +| `CODEX_MODEL` | No | Codex model name (default: `databricks-gpt-5-5`) | | `GEMINI_MODEL` | No | Gemini model name (default: `databricks-gemini-2-5-pro`) | | `HERMES_MODEL` | No | Hermes model name (default: `databricks-claude-opus-4-7`) | | `DATABRICKS_GATEWAY_HOST` | No | AI Gateway URL override. Auto-discovered from `DATABRICKS_WORKSPACE_ID` if unset. Falls back to direct model serving if neither is available | diff --git a/setup_claude.py b/setup_claude.py index 725ad4d..e42cd69 100644 --- a/setup_claude.py +++ b/setup_claude.py @@ -31,10 +31,10 @@ settings = { "env": { - "ANTHROPIC_MODEL": os.environ.get("ANTHROPIC_MODEL", "databricks-claude-opus-4-6"), + "ANTHROPIC_MODEL": os.environ.get("ANTHROPIC_MODEL", "databricks-claude-opus-4-7"), "ANTHROPIC_BASE_URL": anthropic_base_url, "ANTHROPIC_AUTH_TOKEN": token, - "ANTHROPIC_DEFAULT_OPUS_MODEL": "databricks-claude-opus-4-6", + "ANTHROPIC_DEFAULT_OPUS_MODEL": "databricks-claude-opus-4-7", "ANTHROPIC_DEFAULT_SONNET_MODEL": "databricks-claude-sonnet-4-6", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "databricks-claude-haiku-4-5", "ANTHROPIC_CUSTOM_HEADERS": "x-databricks-use-coding-agent-mode: true", diff --git a/setup_codex.py b/setup_codex.py index a0f3b72..d546708 100644 --- a/setup_codex.py +++ b/setup_codex.py @@ -9,6 +9,7 @@ Auth: Bearer token via DATABRICKS_TOKEN environment variable. """ import os +import shutil import subprocess from pathlib import Path @@ -22,7 +23,7 @@ host = os.environ.get("DATABRICKS_HOST", "") token = os.environ.get("DATABRICKS_TOKEN", "") -codex_model = os.environ.get("CODEX_MODEL", "databricks-gpt-5-3-codex") +codex_model = os.environ.get("CODEX_MODEL", "databricks-gpt-5-5") # 1. Install Codex CLI into ~/.local/bin (always, even without token) local_bin = home / ".local" / "bin" @@ -75,6 +76,14 @@ codex_dir = home / ".codex" codex_dir.mkdir(exist_ok=True) +# Copy bundled Databricks model catalog into ~/.codex so it can be referenced +# by relative path in config.toml (codex resolves relatives against CODEX_HOME). +catalog_src = Path(__file__).parent / ".codex" / "databricks-models.json" +catalog_dst = codex_dir / "databricks-models.json" +if catalog_src.exists() and catalog_src.resolve() != catalog_dst.resolve(): + shutil.copyfile(catalog_src, catalog_dst) + print(f"Codex model catalog copied: {catalog_dst}") + # Codex CLI uses TOML config with custom model_providers config_content = f"""# Databricks Model Serving Configuration for Codex CLI # Generated by setup_codex.py @@ -82,6 +91,7 @@ # Active model and provider model = "{codex_model}" model_provider = "databricks" +model_catalog_json = "databricks-models.json" # Disable web_search - not supported by Databricks Responses API web_search = "disabled" @@ -110,7 +120,22 @@ env_path.chmod(0o600) print(f"Codex CLI env configured: {env_path}") -# 5. Adapt CLAUDE.md to AGENTS.md for Codex +# 5. Copy Claude skills into ~/.agents/skills/ where Codex discovers them. +# Codex searches `$HOME/.agents/skills/` plus `.agents/skills/` walking up +# from cwd; both resolve to the same path on the deployed app since +# HOME == repo root, and the user-level lookup also covers local dev. +claude_skills_dir = home / ".claude" / "skills" +codex_skills_dir = home / ".agents" / "skills" +if claude_skills_dir.exists(): + codex_skills_dir.parent.mkdir(exist_ok=True) + if codex_skills_dir.exists(): + shutil.rmtree(codex_skills_dir) + shutil.copytree(claude_skills_dir, codex_skills_dir) + print(f"Skills copied: {claude_skills_dir} -> {codex_skills_dir}") +else: + print(f"No Claude skills found at {claude_skills_dir}, skipping copy") + +# 6. Adapt CLAUDE.md to AGENTS.md for Codex # Look for CLAUDE.md in common locations claude_md_locations = [ Path(__file__).parent / "CLAUDE.md", # Same directory as setup script