Skip to content

feat(provider): add Droid SDK provider#82

Merged
aaditagrawal merged 5 commits into
mainfrom
integrate/droid-sdk-provider-2026-05-16
May 16, 2026
Merged

feat(provider): add Droid SDK provider#82
aaditagrawal merged 5 commits into
mainfrom
integrate/droid-sdk-provider-2026-05-16

Conversation

@aaditagrawal
Copy link
Copy Markdown
Owner

@aaditagrawal aaditagrawal commented May 16, 2026

What Changed

  • Added Droid provider support across the server adapter, model/runtime contracts, and web provider UI.
  • Wired Droid runtime mode presentation, provider settings metadata, and adapter/provider tests.
  • Hardened Droid lifecycle handling by rejecting concurrent turns, emitting settled interaction events during shutdown, and avoiding duplicate assistant completions from SDK block IDs.
  • Updated the orchestration integration harness receipt subscription and shutdown handling so test receipts are not missed and disposal failures are reported accurately.

Why

Droid needs to behave like a first-class provider without destabilizing existing providers or the local fork UX. The review fixes prevent shared Droid session state from being clobbered by overlapping turns, keep composer controls safe during provider switches, and make integration harness cleanup/debuggability more reliable.

Validation

  • bun fmt
  • bun lint
  • bun typecheck
  • bun run --cwd apps/server test src/provider/Layers/DroidAdapter.test.ts src/persistence/Migrations/021_RepairProjectionThreadProposedPlanImplementationColumns.test.ts src/persistence/Migrations/029_ProjectionThreadDetailOrderingIndexes.test.ts src/provider/Layers/GeminiCliAdapter.test.ts src/provider/Layers/CodexAdapter.test.ts src/provider/Layers/ProviderRegistry.test.ts

Summary by CodeRabbit

  • New Features

    • Added Droid provider (Early Access) as a selectable provider with icon, settings, and model discovery
    • Introduced "medium-access" runtime mode and exposed it in runtime-mode UI/options
  • Behavior Changes / Bug Fixes

    • Runtime-mode selection now normalizes per-provider and persists to composer drafts
    • Provider list and picker include Droid (available/new) where applicable
    • Checkpoint revert is blocked for Droid sessions to prevent unsupported reverts

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 483b4e20-4b6f-43b8-a887-f0b40c4522cf

📥 Commits

Reviewing files that changed from the base of the PR and between 2d1a900 and cb99339.

📒 Files selected for processing (2)
  • apps/server/src/provider/Layers/DroidAdapter.test.ts
  • apps/web/src/components/ChatView.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/components/ChatView.tsx
  • apps/server/src/provider/Layers/DroidAdapter.test.ts

📝 Walkthrough

Walkthrough

Adds a first-party Droid provider: contracts and settings, server driver and adapter (session/turn lifecycle, SDK mappings, runtime-event translation, attachment resolver), model discovery/status checks, comprehensive tests, web UI integration (icons, provider-aware runtime-mode), and orchestrator-harness receipt/rollback updates.

Changes

Droid Provider Implementation and Integration

Layer / File(s) Summary
Contracts & settings
packages/contracts/src/model.ts, packages/contracts/src/orchestration.ts, packages/contracts/src/providerRuntime.ts, packages/contracts/src/settings.ts
Register DROID_DRIVER_KIND, add medium-access RuntimeMode, extend runtime raw sources with droid.sdk.*, and add DroidSettings schema wired into ServerSettings and patches.
Driver wiring & packaging
apps/server/package.json, apps/server/src/provider/Drivers/DroidDriver.ts, apps/server/src/provider/builtInDrivers.ts
Add @factory/droid-sdk dep, implement DroidDriver create effect, environment type, snapshot stamping, unsupported text-generation stub, and register driver in built-in drivers.
Provider status & model discovery
apps/server/src/provider/Layers/DroidProvider.ts, apps/server/src/provider/Layers/DroidProvider.test.ts
Implement CLI --version check with timeout, optional SDK discovery with timeout, model mapping/deduplication, pending provider draft, and tests for disabled state and discovery cancellation.
Adapter types, SDK mappings & attachments
apps/server/src/provider/droid/DroidAdapterTypes.ts, apps/server/src/provider/droid/DroidSdkMappings.ts, apps/server/src/provider/droid/DroidAttachmentResolver.ts
Add adapter contracts/types, map Droid SDK shapes to canonical enums/types, normalize ask-user/permission payloads, compute token snapshots, and resolve attachments to base64 images with MIME validation.
Adapter implementation, runtime events & tests
apps/server/src/provider/Layers/DroidAdapter.ts, apps/server/src/provider/droid/DroidRuntimeEvents.ts, apps/server/src/provider/Layers/DroidAdapter.test.ts
Implement makeDroidAdapter (session/turn lifecycle, permission/user-input flows, event queue), handleDroidMessage event translations, and extensive adapter tests covering streaming, token aggregation, permissions, spec-mode, lifecycle, rollback, and error paths.
Web UI: runtime-mode presentation & composer wiring
apps/web/src/components/chat/runtimeModePresentation.ts, apps/web/src/components/chat/runtimeModePresentation.test.ts, apps/web/src/components/chat/ChatComposer.tsx, apps/web/src/components/ChatView.tsx, apps/web/src/components/chat/CompactComposerControlsMenu.tsx
Introduce provider-specific runtime-mode metadata (labels/descriptions/icons), include medium-access only for Droid, normalize runtime-mode for provider changes, and make composer controls provider-aware with tests.
Web UI: icons, metadata & session options
apps/web/src/components/Icons.tsx, apps/web/src/components/chat/providerIconUtils.ts, apps/web/src/components/settings/providerDriverMeta.ts, apps/web/src/session-logic.ts, apps/web/src/session-logic.test.ts, apps/web/src/components/KeybindingsToast.browser.tsx, apps/web/src/components/chat/MessagesTimeline.test.tsx
Add DroidIcon, wire provider icon/metadata and Droid settings schema into client definitions, add Droid to PROVIDER_OPTIONS, default-disable Droid in test fixtures, and adjust tests/timeout.
Orchestration harness & checkpoint reactor
apps/server/integration/OrchestrationEngineHarness.integration.ts, apps/server/src/orchestration/Layers/CheckpointReactor.ts, apps/server/src/orchestration/Layers/CheckpointReactor.test.ts
Replace test receipt wiring with PubSub-backed RuntimeReceiptBus and in-memory receipt history, update waitForThread/waitForReceipt logic, supply RepositoryIdentityResolver resolving to null, add 5s shutdown timeout with warnings, and add a droid-specific revert failure guard with test coverage.

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

  • aaditagrawal/t3code#51: Upstream changes touching orchestration receipt bus/test stream wiring that align with the harness receipt bus updates in this PR.

"🐰 I hopped through code at dusk,
Droid sessions woke with quiet musk.
Medium-access paths now thread,
Events and tokens softly spread.
Tests clap paws — the feature's fled."

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(provider): add Droid SDK provider' clearly and concisely summarizes the primary change: introducing Droid provider support.
Description check ✅ Passed The PR description includes 'What Changed', 'Why', and 'Validation' sections covering implementation scope, business rationale, and testing verification.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch integrate/droid-sdk-provider-2026-05-16

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). labels May 16, 2026
@aaditagrawal aaditagrawal force-pushed the sync/upstream-main-2026-05-16 branch from 7bd8081 to e441260 Compare May 16, 2026 10:16
@aaditagrawal aaditagrawal force-pushed the integrate/droid-sdk-provider-2026-05-16 branch from 276ed03 to f4d27b1 Compare May 16, 2026 11:04
@aaditagrawal aaditagrawal changed the base branch from sync/upstream-main-2026-05-16 to main May 16, 2026 11:04
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
apps/web/src/components/settings/providerDriverMeta.ts (1)

78-84: ⚡ Quick win

Consider a more user-friendly badge label.

The badgeLabel: "WIP" is developer-focused terminology. For consistency with the Cursor provider and a more polished user experience, consider using "Early Access" or "Preview" instead of "WIP".

Suggested refinement
   {
     value: ProviderDriverKind.make("droid"),
     label: "Droid",
     icon: DroidIcon,
-    badgeLabel: "WIP",
+    badgeLabel: "Early Access",
     settingsSchema: DroidSettings,
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/components/settings/providerDriverMeta.ts` around lines 78 - 84,
The badgeLabel for the Droid provider is developer-focused ("WIP"); update the
entry where ProviderDriverKind.make("droid") is configured (the object with
label "Droid", icon DroidIcon, settingsSchema DroidSettings) to use a
user-facing badgeLabel such as "Early Access" or "Preview" instead of "WIP" to
match the Cursor provider and improve UX.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/server/integration/OrchestrationEngineHarness.integration.ts`:
- Around line 570-578: The current shutdown pipeline uses Effect.timeout on
shutdown and then catchCause which treats any failure (including real
Scope.close/runtime.dispose errors) as a timeout; modify the pipeline so timeout
handling is explicit: replace Effect.timeout("5 seconds") + catchCause with
either Effect.timeoutOption("5 seconds") and log a timeout only when it returns
a None, or keep Effect.timeout("5 seconds") but in the Effect.catchCause handler
inspect the cause (using Cause.isFailType(cause) && cause.error instanceof
TimeoutException) and only log the "disposal timed out" message for
TimeoutException while rethrowing or logging other causes appropriately; target
the shutdown pipeline where shutdown, Effect.timeout, Effect.catchCause, and
TimeoutException are used.
- Around line 505-537: The durable fallback in
readMatchingReceipt/waitForReceipt cannot reconstruct
checkpoint.baseline.captured and may miss it if emitted before receiptHistory is
attached; fix by subscribing/attaching receiptHistory before starting the
reactor (i.e., ensure receiptHistory is initialized and its Ref is populated
prior to calling reactor.start or any reactor startup helper), or alternatively
persist/emmit checkpoint.baseline.captured into the durable event stream (so
engine.readEvents can replay it) and extend the durableReceipts mapping in
readMatchingReceipt to reconstruct that receipt type.

In `@apps/server/src/provider/droid/DroidRuntimeEvents.ts`:
- Around line 121-126: The CreateMessage completion uses firstTextBlock.id which
can differ from the `${message.messageId}-${index}` keys used earlier, causing
duplicate completions; change the completedItemId calculation in
DroidRuntimeEvents (replace the logic around
firstTextIndex/firstTextBlock/completedItemId) to always use the adapter's
index-based key when a text block exists — i.e., if firstTextIndex >= 0 set
completedItemId = `${message.messageId}-${firstTextIndex}`, otherwise fall back
to message.messageId — and keep activeCompletedAssistantItems checks using that
same completedItemId.

In `@apps/server/src/provider/Layers/DroidAdapter.ts`:
- Around line 264-299: The sendTurn implementation may start a second turn for
the same thread and then overwrite shared context fields (context.activeAbort,
context.activeAssistantItems, context.activeThinkingItems,
context.activeCompletedAssistantItems, activeTokenUsageBaseline), so before
mutating the context in sendTurn (function sendTurn) check the session's current
status/activeTurnId (from sessions.get(input.threadId) / context.status) and, if
a turn is already running, immediately return a ProviderAdapterValidationError
(same shape used elsewhere) rejecting concurrent sendTurn calls for that thread;
perform this guard before creating the AbortController, generating turnId,
pushing to context.turns, or calling updateDroidContextSession to ensure shared
state is not clobbered.

In `@apps/web/src/components/chat/ChatComposer.tsx`:
- Around line 163-166: The code dereferences runtimeModeOption (from
getRuntimeModeConfig(props.provider)) without checking it, which can crash if
props.runtimeMode is stale; update ChatComposer to first check that
runtimeModeOption is defined before accessing RuntimeModeIcon or other
properties (e.g., wrap const RuntimeModeIcon = runtimeModeOption?.icon or
early-return/render a safe fallback when runtimeModeOption is undefined), and
apply the same guard around the later usages (lines ~197-209) where
runtimeModeOption or its properties are read so provider switches cannot cause
undefined dereference.

---

Nitpick comments:
In `@apps/web/src/components/settings/providerDriverMeta.ts`:
- Around line 78-84: The badgeLabel for the Droid provider is developer-focused
("WIP"); update the entry where ProviderDriverKind.make("droid") is configured
(the object with label "Droid", icon DroidIcon, settingsSchema DroidSettings) to
use a user-facing badgeLabel such as "Early Access" or "Preview" instead of
"WIP" to match the Cursor provider and improve UX.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea79df35-aa1b-438d-9a15-0e7f5b7db441

📥 Commits

Reviewing files that changed from the base of the PR and between 62346b1 and f4d27b1.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • apps/server/integration/OrchestrationEngineHarness.integration.ts
  • apps/server/package.json
  • apps/server/src/provider/Drivers/DroidDriver.ts
  • apps/server/src/provider/Layers/CodexSessionRuntime.ts
  • apps/server/src/provider/Layers/DroidAdapter.test.ts
  • apps/server/src/provider/Layers/DroidAdapter.ts
  • apps/server/src/provider/Layers/DroidProvider.test.ts
  • apps/server/src/provider/Layers/DroidProvider.ts
  • apps/server/src/provider/Layers/ProviderRegistry.test.ts
  • apps/server/src/provider/builtInDrivers.ts
  • apps/server/src/provider/droid/DroidAdapterTypes.ts
  • apps/server/src/provider/droid/DroidAttachmentResolver.ts
  • apps/server/src/provider/droid/DroidRuntimeEvents.ts
  • apps/server/src/provider/droid/DroidSdkMappings.ts
  • apps/web/src/components/ChatView.tsx
  • apps/web/src/components/Icons.tsx
  • apps/web/src/components/KeybindingsToast.browser.tsx
  • apps/web/src/components/chat/ChatComposer.tsx
  • apps/web/src/components/chat/CompactComposerControlsMenu.browser.tsx
  • apps/web/src/components/chat/CompactComposerControlsMenu.tsx
  • apps/web/src/components/chat/MessagesTimeline.test.tsx
  • apps/web/src/components/chat/providerIconUtils.ts
  • apps/web/src/components/chat/runtimeModePresentation.test.ts
  • apps/web/src/components/chat/runtimeModePresentation.ts
  • apps/web/src/components/settings/providerDriverMeta.ts
  • apps/web/src/session-logic.test.ts
  • apps/web/src/session-logic.ts
  • packages/contracts/src/model.ts
  • packages/contracts/src/orchestration.ts
  • packages/contracts/src/providerRuntime.ts
  • packages/contracts/src/settings.ts

Comment thread apps/server/integration/OrchestrationEngineHarness.integration.ts
Comment thread apps/server/integration/OrchestrationEngineHarness.integration.ts Outdated
Comment thread apps/server/src/provider/droid/DroidRuntimeEvents.ts
Comment thread apps/server/src/provider/Layers/DroidAdapter.ts
Comment thread apps/web/src/components/chat/ChatComposer.tsx
@aaditagrawal
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/server/src/provider/Layers/DroidAdapter.test.ts`:
- Line 162: The test is calling Array.from(...) on the result of
Effect.timeout(...) which yields an Option wrapping the chunk; update each
occurrence (e.g., where events is created from yield*
Fiber.join(eventsFiber).pipe(Effect.timeout("2 seconds"))) to unwrap the Option
first by checking that the returned value has _tag === "Some" (or using the
Option match), then call Array.from(...) on the inner chunk (e.g., the
Some.value) to get the actual events; apply the same change to all similar uses
of Fiber.join(...).pipe(Effect.timeout(...)) in this file so tests inspect the
collected events rather than a single Some wrapper.

In `@apps/web/src/components/ChatView.tsx`:
- Around line 1261-1286: providerConfigLoaded is too broad and can be true for a
fallback config, causing resolveSelectableProvider to pick a wrong provider and
persist a downgraded runtimeMode; change the gating so normalization only
happens when the active provider set can actually resolve the target: compute
whether resolveSelectableProvider(providerStatuses, requestedProvider ??
ProviderDriverKind.make("codex")) equals the intended provider (or, if
lockedProvider is set, equals lockedProvider) and only then derive
selectedProvider/runtimeMode and call
setComposerDraftRuntimeMode/setDraftThreadContext; otherwise keep rawRuntimeMode
and avoid writing until the true environment config can resolve the provider
(use the existing symbols requestedProvider, lockedProvider,
resolveSelectableProvider, providerStatuses, selectedProvider, runtimeMode,
rawRuntimeMode, setComposerDraftRuntimeMode, setDraftThreadContext,
isLocalDraftThread).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 909cee02-b621-4ef6-acf4-2734c5c2c2e9

📥 Commits

Reviewing files that changed from the base of the PR and between 50482cb and 2d1a900.

📒 Files selected for processing (9)
  • apps/server/src/orchestration/Layers/CheckpointReactor.test.ts
  • apps/server/src/orchestration/Layers/CheckpointReactor.ts
  • apps/server/src/provider/Layers/DroidAdapter.test.ts
  • apps/server/src/provider/Layers/DroidAdapter.ts
  • apps/server/src/provider/Layers/DroidProvider.test.ts
  • apps/server/src/provider/Layers/DroidProvider.ts
  • apps/server/src/provider/droid/DroidAdapterTypes.ts
  • apps/server/src/provider/droid/DroidRuntimeEvents.ts
  • apps/web/src/components/ChatView.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/server/src/provider/droid/DroidAdapterTypes.ts
  • apps/server/src/provider/droid/DroidRuntimeEvents.ts
  • apps/server/src/provider/Layers/DroidProvider.ts

Comment thread apps/server/src/provider/Layers/DroidAdapter.test.ts Outdated
Comment thread apps/web/src/components/ChatView.tsx
@aaditagrawal
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aaditagrawal aaditagrawal merged commit 969af83 into main May 16, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). 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.

1 participant