Skip to content

features reasoning and models

Nik edited this page May 30, 2026 · 2 revisions

Reasoning and models

Active contributors: Nik, Ran

Purpose

DroidProxy exposes a fixed catalog of models that Factory Droid can use as custom models. Each model is defined once in src/Sources/DroidProxyModelCatalog.swift, then written into Factory's ~/.factory/settings.json customModels array by the Apply button in src/Sources/SettingsView.swift. The catalog carries each model's supported reasoning levels, but the proxy never injects reasoning. Droid CLI's per-session model picker reads the native reasoning metadata DroidProxy registers and forwards the chosen level upstream unchanged.

Model catalog

The full catalog from src/Sources/DroidProxyModelCatalog.swift. Antigravity, Kimi, and Cursor models all use provider: "openai" (or generic-chat-completion-api for Cursor) with a /v1 base URL so Droid sends POST /v1/chat/completions.

Display name baseModel idSlug providerKey levels (default) max tokens baseURL
Opus 4.8 claude-opus-4-8 opus-4-8 claude low/medium/high/xhigh/max (xhigh) 128000 http://localhost:8317
Sonnet 4.6 claude-sonnet-4-6 sonnet-4-6 claude low/medium/high/max (high) 64000 http://localhost:8317
GPT 5.2 gpt-5.2 gpt-5.2 codex low/medium/high/xhigh (high) 128000 http://localhost:8317/v1
GPT 5.3 Codex gpt-5.3-codex gpt-5.3-codex codex low/medium/high/xhigh (high) 128000 http://localhost:8317/v1
GPT 5.4 gpt-5.4 gpt-5.4 codex low/medium/high/xhigh (high) 128000 http://localhost:8317/v1
GPT 5.5 gpt-5.5 gpt-5.5 codex low/medium/high/xhigh (high) 128000 http://localhost:8317/v1
Gemini 3.1 Pro (High) gemini-pro-agent antigravity-gemini-3.1-pro antigravity high (high) 65536 http://localhost:8317/v1
Gemini 3.1 Pro (Low) gemini-3.1-pro-low gemini-3.1-pro-low antigravity low (low) 65536 http://localhost:8317/v1
Gemini 3 Flash gemini-3-flash antigravity-gemini-3-flash antigravity high (high) 65536 http://localhost:8317/v1
Gemini 3.5 Flash gemini-3-flash-agent gemini-3.5-flash antigravity medium/high (high) 65536 http://localhost:8317/v1
Gemini 3.5 Flash (Low) gemini-3.5-flash-low gemini-3.5-flash-low antigravity low (low) 65536 http://localhost:8317/v1
Gemini 3.1 Flash Lite gemini-3.1-flash-lite gemini-3.1-flash-lite antigravity high (high) 65536 http://localhost:8317/v1
Claude Sonnet 4.6 (Thinking) ag-c46s-thinking ag-c46s-thinking antigravity high (high) 64000 http://localhost:8317/v1
Claude Opus 4.6 (Thinking) ag-c46o-thinking ag-c46o-thinking antigravity high (high) 64000 http://localhost:8317/v1
GPT-OSS 120B (Medium) gpt-oss-120b-medium gpt-oss-120b-medium antigravity medium (medium) 32768 http://localhost:8317/v1
Kimi K2.6 kimi-k2.6 kimi-k2.6 kimi high (high) 262144 http://localhost:8317/v1
Cursor Composer 2.5 (beta) cursor-composer-2.5 cursor-composer-2.5 cursor high (high) 128000 http://localhost:8317/v1
Cursor Small (beta) cursor-small cursor-small cursor high (high) 64000 http://localhost:8317/v1

The two Cursor models are appended only when the BETA_FLAG UserDefaults flag is on; they use provider: "generic-chat-completion-api". The Antigravity models are built by the antigravityModel(...) helper, which fixes provider: "openai", providerKey: "antigravity", and baseURL: "http://localhost:8317/v1".

Key abstractions

Type Role
DroidProxyModelKind Enum tagging each definition: claudeAdaptive, codex, kimi, antigravity, cursor.
DroidProxyThinkingLevel A reasoning level as value (low/medium/high/xhigh/max) plus displayName.
DroidProxyModelDefinition One model: baseModel, idSlug, displayName, maxOutputTokens, provider, providerKey, baseURL, kind, levels, defaultLevelValue.
simpleID Computed custom:droidproxy:<idSlug> — the stable Factory id for the model.
settingsEntry Computed [String: Any] matching Factory's custom-model schema. Embeds enableThinking: true and a single reasoningEffort (the model's defaultLevelValue, or the only level when there is exactly one) when levels is non-empty. Antigravity entries prefix the display name with Antigravity:.
DroidProxyModelCatalog.definitions The ordered list of all definitions (Cursor entries gated by BETA_FLAG).
settingsModels(providerIsEnabled:) Maps definitions to settingsEntry dicts, skipping any whose providerKey is disabled.
allSettingsIDs Set of every simpleID, used to detect and remove prior DroidProxy entries.

How it works

Apply flow (writing settings.json)

applyFactoryCustomModels() in src/Sources/SettingsView.swift is the writer.

graph TD
    A[User clicks Apply / Re-apply] --> B[Read ~/.factory/settings.json]
    B --> C[Take existing customModels array]
    C --> D[Remove entries whose id is in allSettingsIDs,\nlegacy ids, custom:droidproxy:*, or custom:CC:*]
    D --> E[enabledFactorySettingsModels:\nsettingsModels filtered by provider enabled state]
    E --> F[Append entries, reindex with index = startIndex + offset]
    F --> G[Write timestamped settings.json.droidproxy-*.bak backup]
    G --> H[Serialize prettyPrinted + sortedKeys]
    H --> I[Unescape backslash-slash to plain slash]
    I --> J[Atomic write to settings.json]
    J --> K[factoryModelsInstalled = true]
Loading

enabledFactorySettingsModels() calls DroidProxyModelCatalog.settingsModels with a closure that maps each providerKey to a ServiceType and checks serverManager.isProviderEnabled. checkFactoryModelsInstalled() compares the set of DroidProxy ids currently in settings.json against the expected enabled set to drive the "Applied" badge and the Apply/Re-apply label.

Request-time alias rewrite

For two Antigravity Claude models, the baseModel sent by Droid is not the backend's model id. ThinkingProxy rewrites it in place (preserving JSON key order) before forwarding:

graph LR
    A[Request model field] --> B{antigravityModelAliases?}
    B -- ag-c46s-thinking --> C[claude-sonnet-4-6]
    B -- ag-c46o-thinking --> D[claude-opus-4-6-thinking]
    B -- otherwise --> E[forwarded unchanged]
Loading

A similar map rewrites cursor-composer-2.5 to composer-2.5. See ThinkingProxy for the full rewrite pipeline.

Key principle

The proxy does not inject reasoning, reasoning_effort, thinking, or output_config. Each settingsEntry advertises enableThinking and a default reasoningEffort; Droid CLI's per-session selector picks the level from that native metadata and sends it in the request body, which the proxy forwards unchanged.

Integration points

  • src/Sources/SettingsView.swift reads the catalog (settingsModels, allSettingsIDs) to write and verify ~/.factory/settings.json.
  • src/Sources/ServerManager.swift supplies isProviderEnabled, which gates whether a provider's models are written.
  • src/Sources/ThinkingProxy.swift performs the Antigravity and Cursor model-alias rewrites at request time.

Entry points for modification (adding a model)

  1. Add a DroidProxyModelDefinition to definitions in src/Sources/DroidProxyModelCatalog.swift (use the antigravityModel(...) helper for Antigravity-routed models).
  2. Set its levels and defaultLevelValue; the single default flows into settingsEntry.reasoningEffort.
  3. If the backend expects a different model id than baseModel, add an entry to antigravityModelAliases (or cursorModelAliases) in src/Sources/ThinkingProxy.swift.
  4. Users click Apply in Settings to write the new entry into ~/.factory/settings.json.

Key source files

File Role
src/Sources/DroidProxyModelCatalog.swift Catalog of model definitions, levels, and settingsEntry schema.
src/Sources/SettingsView.swift applyFactoryCustomModels, enabledFactorySettingsModels, checkFactoryModelsInstalled.
src/Sources/ThinkingProxy.swift Request-time Antigravity/Cursor model-alias rewriting.
src/Sources/AuthStatus.swift ServiceType, which maps providerKeys to provider enable state.

Related

Clone this wiki locally