Skip to content

Add Droid SDK provider#2689

Open
0xSero wants to merge 7 commits into
pingdotgg:mainfrom
0xSero:ai/droid-sdk-provider
Open

Add Droid SDK provider#2689
0xSero wants to merge 7 commits into
pingdotgg:mainfrom
0xSero:ai/droid-sdk-provider

Conversation

@0xSero
Copy link
Copy Markdown

@0xSero 0xSero commented May 14, 2026

Intention

Add Droid as a first-class T3 Code provider using Factory's TypeScript SDK: https://github.com/Factory-AI/droid-sdk-typescript

This is still WIP while we validate more real Droid permission, file, MCP, auth, and long-running streaming flows.

What this adds

  • Adds droid to the shared provider, model, settings, runtime source, and driver contracts.
  • Registers a managed Droid provider driver plus inventory probe.
  • Wraps createSession / resumeSession from @factory/droid-sdk in a T3 provider adapter.
  • Supports Droid session start, resume, stop, interrupt, and in-session model / reasoning updates.
  • Streams assistant text, reasoning text, tool progress/results, token usage, MCP/auth status, title updates, turn completion, and runtime errors into canonical T3 runtime events.
  • Routes Droid permission callbacks through T3 approval requests.
  • Routes Droid ask-user callbacks through the existing structured user-input flow.
  • Sends supported image attachments (gif, jpeg, png, webp) as base64 SDK image sources resolved through the existing attachment store.
  • Discovers SDK-reported Droid models from initResult.availableModels, including user/custom models, while preserving custom model ids so duplicate underlying models remain selectable.
  • Adds Droid UI presence in Provider Settings and the model picker, including the provided icon.

Implementation shape

The Droid adapter has been split by responsibility instead of keeping one large file:

  • DroidAdapter.ts: session lifecycle and adapter orchestration.
  • provider/droid/DroidRuntimeEvents.ts: SDK message to T3 runtime event projection.
  • provider/droid/DroidSdkMappings.ts: SDK model, access, reasoning, usage, approval, and user-input mappings.
  • provider/droid/DroidAttachmentResolver.ts: attachment MIME validation and image loading.
  • provider/droid/DroidAdapterTypes.ts: shared Droid adapter types.

Security / safety notes

  • Droid remains disabled by default.
  • No SDK secrets, pairing tokens, or provider auth payloads are intentionally logged.
  • Permission requests are mediated through T3 approval events and default to cancellation on missing/stale sessions.
  • Attachment paths are resolved through the existing attachment store helper; unsupported MIME types fail before SDK submission.
  • The Droid binary path is configurable but defaults to droid; prompt content is sent through the SDK rather than shell interpolation.
  • Model discovery uses a short-lived SDK session in a temp cwd and closes it immediately after reading init metadata.

Validation

  • Real Droid CLI query: droid exec --model glm-5.1 --cwd /tmp ... returned droid-pong.
  • Live SDK model discovery returned 67 models, including 38 user/custom models.
  • Local T3 model picker showed custom Droid models such as HomeLab - GLM-5.1, HomeLab - Trinity-Large-Thinking, Direct - GPT-5.5-Fast-xHigh, and Direct - GPT-5.5-Low.
  • Review comments addressed: missing-session reads now fail; Droid rollback now honors numTurns; streaming, thinking, access-mode mapping, and custom model discovery were updated.
  • bun fmt passed.
  • bun lint passed with existing unrelated web warnings.
  • bun typecheck passed.
  • Focused Droid tests passed: cd apps/server && bun run test src/provider/Layers/DroidAdapter.test.ts src/provider/Layers/DroidProvider.test.ts.
  • Full bun run test previously passed; after rebasing, one full parallel run hit three unrelated web timeout failures, and rerunning those exact files in isolation passed.

Note

Add Droid SDK provider with session management, model discovery, and UI integration

  • Adds a new droid provider driver backed by @factory/droid-sdk, including a CLI health check (--version), model discovery via SDK session, and periodic status refresh emitting a ServerProviderDraft.
  • Introduces DroidAdapter supporting session start/resume, turn streaming, permission and user-input routing, model/reasoning updates, spec mode on plan interaction, interruption, and thread snapshot management.
  • Adds DroidProvider layer with CLI probing, version parsing, timeout handling, and model list assembly (SDK-discovered + user custom models via settings fallback).
  • Extends contracts with the droid provider kind, DroidSettings schema (enabled, binaryPath, customModels), medium-access runtime mode, and droid.sdk.* event source literals.
  • Adds provider-specific runtime mode presentation in the web UI: CompactComposerControlsMenu and ComposerFooterModeControls now render provider-dependent access mode labels and options (Droid uses Off/Low/Medium/High).
  • Risk: medium-access is a new runtime mode that maps to on-request approval policy and workspace-write sandbox — existing clients sending this value will now route differently than the previous default (danger-full-access).

Macroscope summarized af7ffb0.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a1e5a618-73a9-4e86-81df-e069d805f494

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 size:XL 500-999 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels May 14, 2026
Comment thread apps/server/src/provider/Layers/DroidAdapter.ts Outdated
@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels May 14, 2026
Comment thread apps/server/src/provider/Layers/DroidAdapter.ts Outdated
@0xSero
Copy link
Copy Markdown
Author

0xSero commented May 15, 2026

Latest Droid follow-up fixes pushed in c72f19b:

  • Fixed streaming by reconciling SDK assistant_text_delta block IDs with final create_message content, so final messages fill missing text without duplicating streamed text.
  • Added final create_message fallback handling for assistant text and thinking blocks when deltas are absent.
  • Passed custom model IDs and reasoning effort into Droid spec mode via enterSpecMode({ specModeModelId, specModeReasoningEffort }) and updateSettings(...), which fixes thinking/spec mode for custom models.
  • Matched Droid access levels to SDK autonomy levels: Off, Low, Medium, High, while keeping Medium visible only for Droid UI.
  • Verified the live app model picker shows user/custom Droid models including Direct - GPT-5.5-Fast-xHigh, and the Droid access menu shows Off/Low/Medium/High.
  • Direct SDK smoke query with custom xHigh model returned droid-smoke-ok.

Validation: bun fmt, focused Droid adapter/provider tests, bun typecheck, bun lint, and full bun run test all pass.

Comment thread apps/server/src/provider/Layers/DroidAdapter.ts
@0xSero
Copy link
Copy Markdown
Author

0xSero commented May 15, 2026

Addressed the unresolved Droid cleanup review thread in b1dabf8. stopSession now treats droid.close() as best-effort cleanup, matching the scoped finalizer behavior, so stopAll() can continue shutting down the remaining sessions even if one SDK close throws.

Added a regression test covering two resumed Droid sessions where one close() fails and verified both sessions are still removed.

Validation:

  • bun fmt
  • bun lint (passes with existing unrelated warnings)
  • bun typecheck
  • cd apps/server && bun run test src/provider/Layers/DroidAdapter.test.ts src/provider/Layers/DroidProvider.test.ts
  • bun run test full suite

Note: the first full-suite run hit a timeout in @t3tools/oxlint-plugin-t3code; that package passed in isolation, then the full suite passed on rerun.

@0xSero 0xSero changed the title WIP: Add Droid SDK provider Add Droid SDK provider May 15, 2026
@0xSero 0xSero marked this pull request as ready for review May 15, 2026 23:25
probe: {
installed: settings.enabled,
version: null,
status: settings.enabled ? "warning" : "warning",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Redundant ternary always returns "warning" for disabled status

Medium Severity

In makePendingDroidProvider, the ternary settings.enabled ? "warning" : "warning" always evaluates to "warning" regardless of whether Droid is enabled or disabled. When settings.enabled is false, the status likely needs to be "disabled" (matching the pattern used by other providers like Cursor, which reports status: "disabled" when the provider is turned off in the existing test assertions).

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6c25239. Configure here.

"auto-accept-edits",
"medium-access",
"full-access",
];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Runtime mode medium-access persists across provider switches

Medium Severity

If a user selects medium-access on a Droid session and then switches to a non-Droid provider, the stored runtimeMode remains medium-access. The non-Droid getRuntimeModeOptions list excludes medium-access, so the Select component would display a value that doesn't appear in its own dropdown options. The user would see "Medium access" as the active selection but couldn't reselect it or see it in the list, leaving the UI in an inconsistent state until they manually pick a different mode.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6c25239. Configure here.

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 15, 2026

Approvability

Verdict: Needs human review

This PR adds a new Droid SDK provider integration with substantial new logic (~1000+ lines across driver, adapter, and provider files), introduces a new 'medium-access' runtime mode, and has three unresolved medium-severity bugs identified in review comments regarding status handling, UI state consistency, and token usage format.

You can customize Macroscope's approvability policy. Learn more.

@0xSero
Copy link
Copy Markdown
Author

0xSero commented May 15, 2026

Split the Droid adapter by responsibility in af7ffb0:

  • DroidAdapter.ts is now 433 lines and only owns session lifecycle / adapter orchestration.
  • provider/droid/DroidRuntimeEvents.ts handles Droid SDK message to runtime event projection.
  • provider/droid/DroidSdkMappings.ts handles SDK enum, model, access, user-input, and usage mappings.
  • provider/droid/DroidAttachmentResolver.ts handles attachment image validation/loading.
  • provider/droid/DroidAdapterTypes.ts holds shared adapter types.

The Droid implementation is now 989 lines total across focused modules instead of one nearly 900-line adapter file.

Validation:

  • bun fmt
  • bun lint (passes with existing unrelated web warnings)
  • bun typecheck
  • focused Droid tests: cd apps/server && bun run test src/provider/Layers/DroidAdapter.test.ts src/provider/Layers/DroidProvider.test.ts
  • full bun run test was rerun after rebase and hit three unrelated web timeout failures under parallel load; rerunning those exact three files in isolation passed: cd apps/web && bun run test src/environments/runtime/service.addSavedEnvironment.test.ts src/environments/runtime/service.threadSubscriptions.test.ts src/components/chat/MessagesTimeline.test.tsx

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit af7ffb0. Configure here.

type: "turn.completed",
payload: {
state: "completed",
...(context.activeTokenUsage ? { usage: context.activeTokenUsage } : {}),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Raw SDK token usage passed instead of canonical format

Medium Severity

The turn.completed event passes context.activeTokenUsage directly, which is a raw SDK TokenUsageUpdate object (with fields like inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens, thinkingTokens). However, the thread.token-usage.updated event in DroidRuntimeEvents.ts properly converts using toTokenUsageSnapshot(message) to produce the canonical format (with fields like usedTokens, cachedInputTokens, reasoningOutputTokens). This inconsistency means downstream consumers reading usage from turn.completed get a different shape than the rest of the system.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit af7ffb0. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant