Skip to content

feat(providers): add proto provider wrapping @protolabsai/sdk#3625

Merged
mabry1985 merged 1 commit into
mainfrom
feat/rip-anthropic-sdk-replace-with-proto-sdk
May 22, 2026
Merged

feat(providers): add proto provider wrapping @protolabsai/sdk#3625
mabry1985 merged 1 commit into
mainfrom
feat/rip-anthropic-sdk-replace-with-proto-sdk

Conversation

@mabry1985
Copy link
Copy Markdown
Contributor

@mabry1985 mabry1985 commented May 22, 2026

Why

We're cutting over from `@anthropic-ai/claude-agent-sdk` to our own `@protolabsai/sdk` (the protoCLI TypeScript SDK at https://github.com/protoLabsAI/protoCLI/tree/dev/packages/sdk-typescript) so we control the full agent stack — multi-provider routing, gateway auth, tool schemas, hook semantics. The proto SDK is API-compatible enough with the Anthropic one to make this surgical, but the field/shape differences make a one-shot rip-out risky on a load-bearing path. So:

  • PR 1 (this one): Add `ProtoProvider` alongside `ClaudeProvider`. Wired into `ProviderFactory` at priority 100, claims only `protolabs/*` models. Existing flows untouched. Live workload through the new provider can be exercised without flipping anything.
  • PR 2 (follow-up, after burn-in): Migrate `sdk-options.ts` to proto types, delete `claude-provider.ts` + `verify-claude-auth.ts` + Claude SDK test fixtures, remove the `@anthropic-ai/claude-agent-sdk` dep, widen `isProtoModel` to claim everything not handled by a more-specific provider.

What this PR adds

`apps/server/src/providers/proto-provider.ts` — new `ProtoProvider` class extending `BaseProvider`. Mirrors `ClaudeProvider`'s contract (`executeQuery`, `detectInstallation`, `getAvailableModels`, `supportsFeature`).

Key shape adapters between our `ExecuteOptions` (Claude-shaped) and proto's `QueryOptions`:

ExecuteOptions field Proto QueryOptions field
`maxTurns` `maxSessionTurns`
`allowedTools` `coreTools`
`disallowedTools` `excludeTools`
`hooks` (Claude matcher arrays) `hookCallbacks` (flat `Record<HookEvent, fn[]>`) — via `adaptHooks()`
permission: `bypassPermissions` permission: `yolo`

Env is built clean (no `process.env` passthrough beyond an allowlist) and routes through the LiteLLM gateway by default — `OPENAI_API_KEY` / `OPENAI_BASE_URL` derived from `GATEWAY_API_KEY` / `GATEWAY_BASE_URL` with a sane default of `https://api.proto-labs.ai/v1\`. Langfuse OTel headers pass through identically to ClaudeProvider so per-turn traces still land in the same dashboards.

`systemPrompt` is honored only in its `string` form for PR 1 — the `SystemPromptPreset` shape in `ExecuteOptions` is Claude-flavored (`preset: 'claude_code'`) and doesn't translate cleanly to proto's `'qwen_code'` preset semantics. PR 2 will surface a first-class preset abstraction at the ExecuteOptions layer.

`apps/server/src/providers/provider-factory.ts` — registers `ProtoProvider` with priority 100 and `isProtoModel` model matcher. Conservative scope: claims only `protolabs/*` model IDs. Existing Claude / Cursor / Codex / OpenCode / Groq / OpenAI-compatible matchers and priorities are untouched, so this is additive.

`apps/server/tests/unit/providers/provider-factory.test.ts` — bumps expected provider count from 6 to 7 and asserts `'proto'` is in the registered set.

`apps/server/package.json` — adds `@protolabsai/sdk@^0.2.0`.

What this PR explicitly does NOT change

  • `ClaudeProvider` keeps working. Every existing flow that resolves to a `claude-*` or alias model still routes through `@anthropic-ai/claude-agent-sdk` exactly as before.
  • `sdk-options.ts` is untouched. The 1000+ lines of option-builder code, the Claude-shaped hook matchers, and the `PostToolUseHookInput` casts all stay until PR 2.
  • `verify-claude-auth.ts` is untouched. It's already inert under gateway-routed chat (fix(chat): route through LiteLLM gateway, default to protolabs/smart #3619) and will be deleted in PR 2 alongside the SDK dep removal.
  • No defaults flip in `DEFAULT_MODELS`. `ProtoProvider` is opt-in via `protolabs/*` model IDs only.

Validation

  • `npm run typecheck` clean across all 21 workspaces
  • `vitest run` in apps/server: 3431 passed, 23 skipped, 0 failed
  • Provider-factory test now asserts 7 providers with `'proto'` in the registered set

Burn-in plan before PR 2

  1. Pick a feature in the board UI and route it through a `protolabs/smart` model (model defaults dropdown picks this up automatically once feat(ui): surface litellm gateway models as the first category in model defaults #3621 lands).
  2. Verify the agent runs end-to-end through `ProtoProvider.executeQuery` — worktree creation, tool calls, hook callbacks, abort, completion.
  3. Compare Langfuse traces against an equivalent Claude SDK run.
  4. Once green, PR 2 deletes the old SDK and Claude-shaped option builders.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ProtoLabs provider integration enabling queries to route through the ProtoLabs gateway with full streaming support.
    • Includes tool permission management and comprehensive error handling with gateway-specific guidance.
    • Configured for secure credential handling with OpenAI-compatible API mapping.
  • Chores

    • Added ProtoLabs SDK dependency.
    • Updated unit tests to reflect new provider registration.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 77fdb64d-694d-40bb-b167-1786daf1131c

📥 Commits

Reviewing files that changed from the base of the PR and between f76bd4b and 0c67e92.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • apps/server/package.json
  • apps/server/src/providers/proto-provider.ts
  • apps/server/src/providers/provider-factory.ts
  • apps/server/tests/unit/providers/provider-factory.test.ts

📝 Walkthrough

Walkthrough

This PR integrates the ProtoLabs SDK as a new provider in the agent execution system. It adds the @protolabsai/sdk dependency, implements a new ProtoProvider class that maps gateway credentials to SDK configuration, adapts Claude-style hooks to SDK format, executes queries with normalized prompts and error classification, registers the provider in the factory with model-based routing, and updates tests to account for the seventh provider.

Changes

ProtoProvider SDK Integration

Layer / File(s) Summary
Proto SDK Dependency
apps/server/package.json
Adds @protolabsai/sdk version ^0.2.0 to runtime dependencies.
ProtoProvider Implementation
apps/server/src/providers/proto-provider.ts
Implements ProtoProvider extending BaseProvider with imports and constants, environment variable builder that maps gateway credentials to OpenAI-compatible SDK config, adaptHooks() to convert Claude-style hook matchers to SDK HookEvent→HookCallback[] form, executeQuery() that validates model id, builds QueryOptions with tool/permission/system-prompt/hook routing, normalizes array prompts to user messages, streams SDK responses as ProviderMessage, and catches/classifies errors with optional rate-limit tips. Also includes detectInstallation() checking gateway env vars, getAvailableModels() returning protolabs/smart and protolabs/fast, supportsFeature() for feature gating, and exported isProtoModel() classifier for protolabs/* model ids.
Provider Factory Registration
apps/server/src/providers/provider-factory.ts
Imports ProtoProvider and isProtoModel, then registers the proto provider with ProtoProvider factory, protolabs alias, isProtoModel matcher, and priority: 100 to route matching models ahead of other providers.
Test Updates
apps/server/tests/unit/providers/provider-factory.test.ts
Updates getAllProviders and checkAllProviders test assertions to expect 7 providers instead of 6, and adds assertion that checkAllProviders() includes the proto key.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant ProtoProvider
  participant SDK
  participant ErrorHandler

  Caller->>ProtoProvider: executeQuery
  ProtoProvider->>ProtoProvider: validate model id
  ProtoProvider->>ProtoProvider: build QueryOptions
  ProtoProvider->>ProtoProvider: normalize prompt
  ProtoProvider->>SDK: stream(options)
  
  alt Success
    SDK-->>ProtoProvider: messages
    ProtoProvider->>ProtoProvider: yield ProviderMessage
    ProtoProvider-->>Caller: stream response
  else Error
    SDK-->>ErrorHandler: error
    ErrorHandler->>ErrorHandler: classify and wrap
    ErrorHandler-->>Caller: throw with context
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A gateway provider hops into the mix,
With hooks and prompts carefully fixed,
SDK calls stream messages bright,
ProtoLabs models take flight,
Routing by name, the integration's complete! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a new ProtoProvider that wraps @protolabsai/sdk. It is concise, specific, and directly reflects the primary purpose of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 feat/rip-anthropic-sdk-replace-with-proto-sdk

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

@github-actions
Copy link
Copy Markdown
Contributor

Code Review — ? finding(s)

Async review running parallel to CodeRabbit. Findings are advisory; not all are merge blockers.

protoLabs Code Review Report

  • Generated: 2026-05-22T09:44:59Z
  • Git head: 546fc8fe3cf675333bfd03258bb0fc8d32862917
  • Features mapped: 3
  • Findings: 0

No findings recorded.

@mabry1985
Copy link
Copy Markdown
Contributor Author

Programmatic burn-in: ✓ green

Built the branch and exercised `ProtoProvider.executeQuery` directly against the gateway. Two passes:

1. Bare query (single-turn, no tools)

```
Provider: proto
Available models: protolabs/smart, protolabs/fast
Installation: { installed: true, method: 'sdk', hasApiKey: true, authenticated: true }

Executing test query through gateway...
[1] type=system subtype=init
[2] type=assistant
[3] type=assistant
assistant text: "\n\nready"
[4] type=result subtype=success
result subtype: success result="\n\nready"

✓ Stream complete: 4 messages, last type=result
```

2. Tool path (read_file)

Wrote a temp file with a one-shot token, asked the agent to read it back:

```
workdir: /var/folders/.../proto-burnin-sfY1xd
expected token: BURNIN-1779443347311

tool_use #1: name=read_file input={"file_path":".../secret.txt"}
result: success "\n\nBURNIN-1779443347311"

Messages: 7, tool calls: 1, token found in output: true
✓ tool path works
```

ProtoProvider spawned the SDK, the SDK routed OPENAI_BASE_URL=https://api.proto-labs.ai/v1, the model dispatched a read_file tool call, and the result stream carried the correct value back through executeQuery's async generator. End-to-end happy path is real.

Both tests under 60s. Hooks and MCP servers weren't exercised — those land in PR 2 once sdk-options.ts is migrated and the real feature pipeline routes through ProtoProvider.

Merging.

@mabry1985 mabry1985 merged commit 555bec5 into main May 22, 2026
7 checks passed
@mabry1985 mabry1985 deleted the feat/rip-anthropic-sdk-replace-with-proto-sdk branch May 22, 2026 09:49
mabry1985 pushed a commit that referenced this pull request May 23, 2026
Minor bump — the first release since the proto SDK cutover, beads
integration, and ~64 commits of fixes / cleanup. Per `npm run
release:prepare` (auto-classified from conventional-commit prefixes).

Highlights since v0.107.1:

- proto SDK is now the primary driver — `@anthropic-ai/claude-agent-sdk`
  ripped out (#3625-#3629). ProtoProvider wraps `@protolabsai/sdk`,
  routes through the LiteLLM gateway, default model `protolabs/smart`.
- beads (`br`) tracker replaces the in-app TODO surface (#3639) — single
  source of truth between UI and crew, JSONL is git-friendly.
- create-new-project picker trimmed: ai-agent-app, design-system, and
  browser-extension starters removed (#3638) — 53k LoC deleted.
- Fault tolerance round (today): #3635/#3613/#3568/#3594/#3596/#3483
  closed — error reasons now reach `feature.statusChangeReason`,
  merged-PR reconciler has a branch-fallback path, escalation router
  no longer self-loops, KnowledgeIngestion and LabsService have path
  containment, branch-name unsafe-char merge gate hard-fails cleanly.
- Significant dead-code purge across UI + server (#3577-#3591) — dead
  routes, services, hooks, view components.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant