Skip to content

feat(provider): add Factory Droid as first-class provider#1

Open
0xSero wants to merge 19 commits into
mainfrom
feature/droid-support
Open

feat(provider): add Factory Droid as first-class provider#1
0xSero wants to merge 19 commits into
mainfrom
feature/droid-support

Conversation

@0xSero
Copy link
Copy Markdown
Owner

@0xSero 0xSero commented Mar 25, 2026

Summary

This PR adds Factory Droid as a first-class provider

What changed

  • Add Factory Droid provider support across server, contracts, shared model resolution, and web composer flows.
  • Persist provider-aware model selections.
  • Expose Droid behavior through provider capabilities.
  • Refactor Droid runtime-event mapping into a dedicated helper module.
  • Restore the README/provider list so Droid is represented correctly.

Diff size

Branch diff against main...feature/droid-support:

  • Commits ahead: 8
  • Files changed: 90
  • Insertions: 5811
  • Deletions: 2127
  • Current size of changed files: 1,978,401 bytes

Top-level breakdown:

  • apps/server/src/provider: 15 files, +1308 / -116
  • apps/server/src/persistence: 10 files, +830 / -112
  • apps/server/src/orchestration: 15 files, +497 / -230
  • apps/web/src/components: 22 files, +1414 / -1067
  • apps/web/src/composerDraftStore.ts: 1 file, +584 / -181
  • packages/contracts/src: 5 files, +242 / -65
  • packages/shared/src: 2 files, +229 / -98

Top refactor commit only (4648f1da):

  • Files changed: 4
  • Insertions: 441
  • Deletions: 219
  • File sizes:
    • README.md: 999 bytes
    • apps/server/src/provider/Layers/FactoryDroidAdapter.ts: 22,352 bytes
    • apps/server/src/provider/Layers/FactoryDroidRuntimeEvents.ts: 7,022 bytes
    • apps/server/src/provider/Layers/FactoryDroidRuntimeEvents.test.ts: 1,658 bytes

Why these files/areas exist

  • apps/server/src/provider/*: provider lifecycle, runtime events, adapter capabilities, registry wiring.
  • apps/server/src/orchestration/*: provider command/runtime integration and projection flow.
  • apps/server/src/persistence/*: migration and projection updates for provider-aware model/session state.
  • apps/web/src/components/*, composerDraftStore.ts, store.ts: provider-aware composer/model selection UX and Droid traits UI.
  • packages/contracts/src/*, packages/shared/src/*: schema and model resolution updates required by both server and web.

Validation

Focused validation for the top refactor commit:

  • bun fmt: passed
  • bun lint: passed with preexisting warnings in web files
  • bun run --cwd apps/server test src/provider/Layers/FactoryDroidRuntimeEvents.test.ts: passed

Known blockers on current branch:

  • bun typecheck fails in preexisting branch files under apps/web and apps/server, including apps/web/src/components/chat/FactoryDroidTraitsPicker.tsx, apps/web/src/components/ChatView.tsx, apps/web/src/composerDraftStore.ts, apps/server/src/orchestration/Layers/ProviderCommandReactor.ts, and apps/server/src/provider/Layers/ClaudeAdapter.ts.

0xSero and others added 17 commits March 25, 2026 11:46
- Add factoryDroid provider adapter using droid CLI stream-jsonrpc protocol
- Implement delta coalescing (50ms) and delayed turn completion (200ms)
  to handle CLI's burst-mode token output without data loss
- Map droid tool calls (create_message/tool_result) to item lifecycle events
- Map session_title_updated and token usage notifications
- Wire provider through contracts, shared model, server layers, and web UI
- Add provider picker, model catalog, settings, health check, and traits picker
- Add incremental domain event application in web store for streaming UX
- Allow explicit provider switching in ProviderCommandReactor
- Allow stateless session recovery for factoryDroid in ProviderService
…ctions

Fixes conflict markers in ChatView.tsx, adds back getModelCapabilities/getDefaultEffort/hasEffortLevel/trimOrNull
that were lost during rebase, updates composerProviderRegistry to use unified TraitsPicker, and fixes test expectations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…se modelSelection

- Add FactoryDroidModelSelection to ModelSelection union so server can decode droid threads
- Add PROVIDER_DISPLAY_NAMES constant for UI display
- Fix store.syncServerReadModel to map modelSelection and defaultModelSelection instead of removed model field
- Fix ProviderCommandReactor to read thread.modelSelection instead of thread.model
- Add missing resolveModelSlugForProvider import to ChatView

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed the section listing supported providers from the README.
- Deduplicate effort API in shared/model.ts: getModelCapabilities now
  delegates to getReasoningEffortOptions instead of maintaining parallel logic
- Remove dead exports (getEffectiveClaudeCodeEffort, unused constant re-exports)
- Inline model slug constants into supportsClaudeX helpers
- Refactor FactoryDroidRuntimeEvents to improve event mapping coverage
- Update FactoryDroidAdapter, ChatView, and store for consistency
…treaming

- Migrate TraitsPicker, ClaudeAdapter, ChatView off ModelCapabilities
  facade to use typed effort API directly (getReasoningEffortOptions,
  resolveReasoningEffortForProvider, supportsClaudeX helpers)
- Fix codex fast mode support in TraitsPicker (was broken by earlier refactor)
- Deduplicate EFFORT_LABELS: single export from shared/model.ts
- Collapse supportsClaudeMaxEffort/supportsClaudeUltrathinkKeyword into aliases
- Remove unused contract imports from model.ts
- Fix doubled droid output: set sawAssistantTextDelta after fallback text
- Fix premature turn completion: cancel idle timer on non-idle state
- Split assistant text across tool use boundaries via segment-based itemIds
  so text renders around tool activity cards instead of one merged block
…nd event mapper

- Delete unused FactoryDroidTraitsPicker.tsx (Droid uses generic TraitsPicker)
- Rewrite FactoryDroidAdapter.ts: compact session context, remove 1.5s startup sleep
  (replaced with spawn-readiness await), consolidate JSON-RPC helpers
- Shrink FactoryDroidRuntimeEvents.ts: deduplicate helpers, inline token usage mapper
- Net reduction: ~365 lines removed across Droid integration files
- Remove getModelCapabilities, getDefaultEffort, hasEffortLevel, EffortLevel,
  ModelCapabilities (only used by tests, not production code)
- Remove dead inferProviderForThreadModel and unused imports from store.ts
- Rewrite facade tests to use direct typed API (getReasoningEffortOptions,
  supportsClaudeFastMode, etc.)
- Net reduction: ~127 lines
Critical fixes:
- Fix 'reasoning' -> 'reasoning_text' (invalid RuntimeContentStreamKind)
- Wrap raw Error throws in typed ProviderAdapterError subtypes
- Fix misleading authStatus:'authenticated' in health check (now 'unknown')
- Deduplicate asObj helper between adapter and runtime events

Dynamic model discovery:
- Add models field to ServerProviderStatus schema
- Parse available models from 'droid exec --help' at startup
- Merge discovered models into web model picker via provider statuses
- Trim hardcoded fallback to 3 core models (was 35)
- Remove stale model aliases
The Droid CLI validates model IDs server-side. Don't reject dynamically
discovered or custom model slugs that aren't in the static fallback list.
Map task_started, task_progress, task_completed, task_notification
notifications from the Droid CLI to task.started/progress/completed
ProviderRuntimeEvents. Recognize Task/subagent tool calls as
collab_agent_tool_call items. Fix missing brace in model parser.
The 4s default timeout was too tight for 'droid exec --help' which
takes ~2s+ to run. Split into separate probes with dedicated timeouts.
…racking

- Handle droid.ask_user RPC by emitting user-input.requested events,
  rendering the questionnaire in the web UI, and responding with the
  Droid CLI's expected format ({cancelled, answers: [{index, question, answer}]})
- Track toolUseId -> itemType in a registry so tool_result events
  emit item.completed with the correct itemType (e.g. collab_agent_tool_call)
  instead of always defaulting to dynamic_tool_call
- Clean up pendingUserInputs and toolUseRegistry on session stop
- Route droid.request_permission through the approval UI flow instead
  of auto-approving. In full-access mode, still auto-approve. In
  approval-required mode, emit request.opened, wait for user decision
  via respondToRequest, then forward the mapped selectedOption to the CLI.
- Implement respondToRequest to resolve pending approval deferreds.
- Hydrate turn items from create_message notifications so readThread
  returns authoritative per-turn item state.
- Replace JSON.stringify equality in sameModelOptions with a
  sorted-key deep compare to avoid order-sensitive mismatches.
- Add clarifying comment that ProviderHealth discovery is cached via
  Fiber (runs once at startup, not on every getStatuses call).
@0xSero 0xSero force-pushed the feature/droid-support branch from 103997c to b37e2cc Compare March 26, 2026 22:17
@BleedingDev
Copy link
Copy Markdown

Will this also integrate missions? Would you welcome me to test it and provide feedback? :)

…apter

Fix two critical bugs in the Factory Droid adapter:

1. Segment-tracking race: incrementSegment() was called BEFORE
   mapFactoryDroidNotification evaluated sawDelta, resetting the flag
   to false. This caused create_message text blocks to be emitted as
   fallbackText even though the same text was already streamed via
   assistant_text_delta, producing visible duplicate/repeated content
   in the chat UI. Especially noticeable around subagent boundaries.

2. Idle timer during user interaction: droid_working_state_changed
   with idle state would schedule the turn-completion timer even while
   ask_user or request_permission was pending. The 200ms idle timer
   would fire and complete the turn prematurely, leaving the session
   stuck in a ready state while droid was still waiting for input.
   After answering, droid would continue generating into a completed
   turn, causing the never-responds / pending hang.

Also refactors the adapter into separate JsonRpcProcess and
TokenCoalescer modules for maintainability.
@0xSero 0xSero marked this pull request as ready for review May 16, 2026 06:27
@github-actions github-actions Bot added size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels May 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants