Skip to content

feat: Example Anthropic provider plugin + plugin-registered provider adapter - #30

Closed
TheArchitectit wants to merge 16 commits into
Doorman11991:masterfrom
TheArchitectit:feat/anthropic-provider-plugin
Closed

feat: Example Anthropic provider plugin + plugin-registered provider adapter#30
TheArchitectit wants to merge 16 commits into
Doorman11991:masterfrom
TheArchitectit:feat/anthropic-provider-plugin

Conversation

@TheArchitectit

Copy link
Copy Markdown
Contributor

Summary

This is PR 3 of 3 in a stacked PR chain implementing the plugin-provider architecture for SmallCode.

This PR adds an example Anthropic provider plugin that demonstrates the full plugin-provider lifecycle, plus a generic adapter for plugin-registered providers.

Changes

Anthropic provider plugin (.smallcode/plugins/anthropic-provider/)

  • plugin.json — manifest with tools, hooks, permissions, and provider declarations
  • adapter.jsAnthropicProviderAdapter wraps the Anthropic API with SmallCode's IModelProvider interface
  • pre-request.js — transforms SmallCode chat format to Anthropic API format (converts tool definitions, adds system messages)
  • post-request.js — normalizes Anthropic responses back to SmallCode format
  • on-error.js — handles Anthropic-specific errors (rate limits, auth failures)
  • init.js — plugin initialization
  • cleanup.js — plugin cleanup

Provider adapter (src/compiled/providers/openai_compat.ts)

  • Added PluginProviderAdapter that wraps plugin-registered providers
  • Handles the mismatch between plugin provider names and OpenAI model identifiers
  • Falls back gracefully when a plugin provider isn't available

How it works

  1. Plugin declares providers in its manifest
  2. PluginLoader.loadAll() calls providerRegistry.register() for each declared provider
  3. resolveProvider() in index.ts checks the registry before falling back to OpenAI-compat
  4. The adapter handles format conversion between SmallCode's chat format and the provider's API

Why this PR exists

The Anthropic provider plugin serves as:

  • A reference implementation for building custom provider plugins
  • A working example of the manifest schema (tools, hooks, permissions, providers)
  • A demonstration of the prompt-inject pattern for RAG/persona injection
  • A test case for the plugin loader's provider registration flow

Plugin structure

.smallcode/plugins/anthropic-provider/
├── plugin.json       # manifest: tools, hooks, permissions, providers
├── adapter.js        # AnthropicProviderAdapter — IModelProvider implementation
├── pre-request.js    # Chat format → Anthropic API format
├── post-request.js   # Anthropic response → SmallCode format
├── on-error.js       # Rate limit / auth error handling
├── init.js           # Plugin initialization
└── cleanup.js        # Plugin cleanup

Stacked with:

🤖 Generated with Claude Code

TheArchitectit and others added 16 commits May 21, 2026 14:47
Implements the core plugin provider infrastructure:
- Add ProviderRegistry singleton for named provider lookup
- Wire plugin providers into chatCompletion and escalation flows
- Support plugin manifest `providers` field in loader
- Register openai_compat and ollama providers on startup

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements a decorator-style provider that wraps any registered
provider and injects custom content into system prompts. Supports
prepend, append, and replace positions. Inner provider is lazily
resolved from the ProviderRegistry at first chat() call.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds plugin init/shutdown lifecycle and hook events for LLM request
interception:

- `init` / `shutdown` manifest fields for startup/teardown handlers
- `pre_request`, `post_request`, `on_error` hook events in chat path
- `session_start`, `session_end` events (wired at session boundaries)
- `runInit()`, `runShutdown()`, `runHooks()` methods on PluginLoader
- Hook event validation with warning for unknown events

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds support for:
- `permissions` manifest field (read/write/execute/network)
- `mcpServers` manifest field for declaring bundled MCP servers
- `capabilities` field on provider declarations (passed to registry)
- getPermissions(), hasPermission(), getMCPServers() accessors
- Default permissions: read-only, no write/execute/network

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PROVIDER_TOOLS was defined but not included in module.exports, causing
TypeError: PROVIDER_TOOLS is not iterable in smallcode.js.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add provider-wizard plugin: /provider command for interactive setup
  of LLM providers (LM Studio, Ollama, OpenRouter, OpenAI, Anthropic,
  DeepSeek, custom). Includes /provider status tool and configure tool
  with validation and discovery.
- Add plugin install scopes (project/user/global) via --scope flag
  with per-scope add/remove commands
- Fix plugin command dispatch: strip leading slash before lookup
- Fix symlink handling in plugin loader: readdirSync with withFileTypes
  doesn't follow symlinks, so isDirectory() returns false for them

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moves the provider wizard out of the plugin system (.smallcode/plugins/provider-wizard/)
into bin/provider-wizard/ as a built-in feature. This makes the wizard always available
without requiring plugin install, and gives the PR its own clear identity.

Changes:
- bin/provider-wizard/ - wizard, status, tool-configure, tool-status (moved from plugin)
- bin/commands.js - /provider command wired directly (not via plugin dispatch)
- bin/executor.js - configure_provider + provider_status tool cases added
- bin/tools.js - PROVIDER_TOOLS schema array (configure_provider, provider_status)
- bin/smallcode.js - ALL_TOOLS includes PROVIDER_TOOLS
- .smallcode/plugins/provider-wizard/ - removed (no longer a plugin)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The model gate at startup was blocking all commands including /provider.
Now /provider commands are dispatched before the model check so users
can configure a provider even with no model set.

Also changes the no-model path to always show the setup TUI instead of
only when a plugin command was registered (provider is now built-in).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Only ollama and LM Studio are truly key-free. Custom endpoints often
need an API key (e.g. vLLM with auth, proxied APIs). Changed custom
provider keyEnv from null to 'SMALLCODE_API_KEY' so the wizard prompts
for it. Also fixed validateApiKey to accept the actual base URL instead
of always using the provider's defaultUrl (which is empty for custom).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The wizard previously only wrote to project .env, causing re-prompting
when switching projects. Now writes to ~/.config/smallcode/.env which
the startup loader already checks as a global fallback. Project .env
still gets written too if it exists, so project-level overrides work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The loader used `break` after finding the first .env, so if a project
had its own .env, the global ~/.config/smallcode/.env was never loaded.
This caused provider config to disappear when switching projects.
Now loads all env files with project-level values taking priority.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The os module was never imported, causing 'os is not defined' fatal
error when the wizard tried to write to ~/.config/smallcode/. This
meant the global env file was never created and provider config
couldn't persist across projects.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The /provider wizard stores the API key as SMALLCODE_API_KEY but the
HTTP auth code only checked OPENAI_API_KEY, ANTHROPIC_API_KEY, and
DEEPSEEK_API_KEY — so custom endpoint keys were never sent, causing
401 Unauthorized on every request.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The /provider command was only dispatched when no model was set.
This adds a handler before the positional prompt branch so users
can reconfigure their provider even after one is already set.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
End-to-end demonstration plugin implementing all 7 features:
- adapter.js: IModelProvider for Anthropic Messages API (tools, vision)
- init.js: API key validation on startup
- cleanup.js: shutdown hook
- pre-request.js / post-request.js / on-error.js: lifecycle hooks
- plugin.json: full manifest with permissions, providers, capabilities

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