Provider 플러그인 빌드하기
이 가이드는 OpenClaw에 모델 provider (LLM)를 추가하는 provider 플러그인을 빌드하는 과정을 안내합니다. 이 가이드를 마치면 모델 카탈로그, API 키 인증, 동적 모델 해석 기능이 있는 provider를 갖게 됩니다.아직 OpenClaw 플러그인을 한 번도 만들어 본 적이 없다면,
먼저 Getting Started를 읽고 기본 패키지
구조와 매니페스트 설정을 확인하세요.
단계별 안내
패키지와 매니페스트
providerAuthEnvVars를 선언하므로 OpenClaw가
플러그인 런타임을 로드하지 않고도 자격 증명을 감지할 수 있습니다. provider 변형이 다른 provider id의 인증을 재사용해야 한다면 providerAuthAliases를 추가하세요. modelSupport
는 선택 사항이며, 런타임 hook이 존재하기 전에 OpenClaw가 acme-large 같은 단축
모델 id에서 provider 플러그인을 자동 로드할 수 있게 해줍니다. provider를
ClawHub에 게시한다면 package.json의 openclaw.compat 및 openclaw.build
필드는 필수입니다.provider 등록
최소한의 provider에는 이것으로 동작하는 provider가 완성됩니다. 이제 사용자는
인증 흐름이 온보딩 중
id, label, auth, catalog가 필요합니다.index.ts
openclaw onboard --acme-ai-api-key <key>를 실행하고
acme-ai/acme-large를 자신의 모델로 선택할 수 있습니다.업스트림 provider가 OpenClaw와 다른 제어 토큰을 사용한다면, 스트림 경로를 교체하는 대신
작은 양방향 텍스트 변환을 추가하세요.input은 전송 전에 최종 시스템 프롬프트와 텍스트 메시지 콘텐츠를 다시 씁니다.
output은 OpenClaw가 자체 제어 마커나 채널 전달을 파싱하기 전에
어시스턴트 텍스트 델타와 최종 텍스트를 다시 씁니다.API 키 인증과 단일 catalog 기반 런타임만 등록하는 번들 provider의 경우,
더 좁은 defineSingleProviderPluginEntry(...) 헬퍼를 우선 사용하세요.models.providers.*, alias, 그리고
에이전트 기본 모델도 함께 패치해야 한다면
openclaw/plugin-sdk/provider-onboard의 preset 헬퍼를 사용하세요. 가장 좁은 헬퍼는
createDefaultModelPresetAppliers(...),
createDefaultModelsPresetAppliers(...), 그리고
createModelCatalogPresetAppliers(...)입니다.provider의 네이티브 엔드포인트가 일반
openai-completions 전송에서 스트리밍 usage block을 지원한다면, provider-id 검사를 하드코딩하는 대신
openclaw/plugin-sdk/provider-catalog-shared의 공유 catalog 헬퍼를 우선 사용하세요.
supportsNativeStreamingUsageCompat(...) 및
applyProviderNativeStreamingUsageCompat(...)는 엔드포인트 capability map에서 지원 여부를 감지하므로,
커스텀 provider id를 사용하는 플러그인에서도 네이티브 Moonshot/DashScope 스타일 엔드포인트가 여전히 opt-in할 수 있습니다.동적 모델 해석 추가
provider가 임의의 모델 ID를 허용한다면(프록시 또는 router처럼)
해석에 네트워크 호출이 필요하다면 비동기 워밍업을 위해
resolveDynamicModel을 추가하세요.prepareDynamicModel을 사용하세요 —
완료된 후 resolveDynamicModel이 다시 실행됩니다.런타임 hook 추가(필요한 경우)
대부분의 provider에는 현재 사용 가능한 replay 계열:
실제 번들 예시:
실제 번들 예시:
catalog + resolveDynamicModel만 필요합니다. provider에
필요한 만큼 hook을 점진적으로 추가하세요.공유 헬퍼 빌더가 이제 가장 일반적인 replay/tool-compat
계열을 다루므로, 플러그인은 보통 각 hook을 하나씩 직접 연결할 필요가 없습니다.| Family | 연결되는 내용 |
|---|---|
openai-compatible | OpenAI 호환 전송을 위한 공유 OpenAI 스타일 replay 정책. 여기에는 tool-call-id 정리, assistant-first 순서 수정, 전송에 필요한 경우 일반 Gemini 턴 검증이 포함됩니다 |
anthropic-by-model | modelId로 선택되는 Claude 인식 replay 정책. 따라서 Anthropic-message 전송은 실제로 해석된 모델이 Claude id일 때만 Claude 전용 thinking-block 정리를 적용받습니다 |
google-gemini | 네이티브 Gemini replay 정책과 bootstrap replay 정리, 그리고 태그된 reasoning-output 모드 |
passthrough-gemini | OpenAI 호환 프록시 전송을 통해 실행되는 Gemini 모델을 위한 Gemini thought-signature 정리. 네이티브 Gemini replay 검증이나 bootstrap 재작성은 활성화하지 않습니다 |
hybrid-anthropic-openai | 하나의 플러그인에서 Anthropic-message와 OpenAI 호환 모델 표면을 혼합하는 provider를 위한 하이브리드 정책. 선택적 Claude 전용 thinking-block 제거는 Anthropic 쪽에만 적용됩니다 |
google및google-gemini-cli:google-geminiopenrouter,kilocode,opencode,opencode-go:passthrough-geminiamazon-bedrock및anthropic-vertex:anthropic-by-modelminimax:hybrid-anthropic-openaimoonshot,ollama,xai,zai:openai-compatible
| Family | 연결되는 내용 |
|---|---|
google-thinking | 공유 스트림 경로에서 Gemini thinking payload 정규화 |
kilocode-thinking | 공유 프록시 스트림 경로에서 Kilo reasoning 래퍼. kilo/auto 및 지원되지 않는 프록시 reasoning id는 주입된 thinking을 건너뜁니다 |
moonshot-thinking | config + /think 수준에서 Moonshot 바이너리 native-thinking payload 매핑 |
minimax-fast-mode | 공유 스트림 경로에서 MiniMax fast-mode 모델 재작성 |
openai-responses-defaults | 공유 네이티브 OpenAI/Codex Responses 래퍼: attribution 헤더, /fast/serviceTier, 텍스트 verbosity, 네이티브 Codex 웹 검색, reasoning-compat payload shaping, Responses 컨텍스트 관리 |
openrouter-thinking | 프록시 경로용 OpenRouter reasoning 래퍼. 지원되지 않는 모델/auto 건너뛰기는 중앙에서 처리 |
tool-stream-default-on | Z.AI 같은 provider를 위한 기본 활성화 tool_stream 래퍼. 명시적으로 비활성화하지 않는 한 도구 스트리밍을 사용합니다 |
google및google-gemini-cli:google-thinkingkilocode:kilocode-thinkingmoonshot:moonshot-thinkingminimax및minimax-portal:minimax-fast-modeopenai및openai-codex:openai-responses-defaultsopenrouter:openrouter-thinkingzai:tool-stream-default-on
openclaw/plugin-sdk/provider-model-shared는 replay-family
enum과 해당 family가 기반으로 삼는 공유 헬퍼도 export합니다. 일반적인 공개 export는
다음과 같습니다.ProviderReplayFamilybuildProviderReplayFamilyHooks(...)buildOpenAICompatibleReplayPolicy(...),buildAnthropicReplayPolicyForModel(...),buildGoogleGeminiReplayPolicy(...), 그리고buildHybridAnthropicOrOpenAIReplayPolicy(...)같은 공유 replay 빌더sanitizeGoogleGeminiReplayHistory(...)및resolveTaggedReasoningOutputMode()같은 Gemini replay 헬퍼resolveProviderEndpoint(...),normalizeProviderId(...),normalizeGooglePreviewModelId(...), 그리고normalizeNativeXaiModelId(...)같은 endpoint/model 헬퍼
openclaw/plugin-sdk/provider-stream는 family builder와
해당 family가 재사용하는 공개 wrapper 헬퍼를 모두 노출합니다. 일반적인 공개 export는
다음과 같습니다.ProviderStreamFamilybuildProviderStreamFamilyHooks(...)composeProviderStreamWrappers(...)- 다음과 같은 공유 OpenAI/Codex wrapper
createOpenAIAttributionHeadersWrapper(...),createOpenAIFastModeWrapper(...),createOpenAIServiceTierWrapper(...),createOpenAIResponsesContextManagementWrapper(...), 그리고createCodexNativeWebSearchWrapper(...) createOpenRouterWrapper(...),createToolStreamWrapper(...),createMinimaxFastModeWrapper(...)같은 공유 프록시/provider wrapper
@openclaw/anthropic-provider는
공개 api.ts /
contract-api.ts 경계를 통해 wrapAnthropicProviderStream, resolveAnthropicBetas,
resolveAnthropicFastMode, resolveAnthropicServiceTier, 그리고
더 낮은 수준의 Anthropic wrapper builder를 export합니다. 이 헬퍼들은
Claude OAuth beta 처리와 context1m 게이팅도 함께 인코딩하므로
Anthropic 전용으로 유지됩니다.다른 번들 provider도 동작이 family 간에
깔끔하게 공유되지 않는 경우 전송별 wrapper를 로컬에 유지합니다. 현재 예시:
번들 xAI 플러그인은 네이티브 xAI Responses shaping을 자체
wrapStreamFn 안에 유지하며, 여기에는 /fast alias 재작성, 기본 tool_stream,
지원되지 않는 strict-tool 정리, 그리고 xAI 전용 reasoning-payload
제거가 포함됩니다.openclaw/plugin-sdk/provider-tools는 현재 하나의 공유
tool-schema family와 공유 schema/compat 헬퍼를 노출합니다.ProviderToolCompatFamily는 현재의 공유 family 목록을 문서화합니다.buildProviderToolCompatFamilyHooks("gemini")는 Gemini 안전 tool schema가 필요한 provider를 위해 Gemini schema 정리 + 진단을 연결합니다.normalizeGeminiToolSchemas(...)와inspectGeminiToolSchemas(...)는 기초가 되는 공개 Gemini schema 헬퍼입니다.resolveXaiModelCompatPatch()는 번들 xAI compat 패치를 반환합니다:toolSchemaProfile: "xai", 지원되지 않는 schema 키워드, 네이티브web_search지원, 그리고 HTML entity 도구 호출 인자 디코딩입니다.applyXaiModelCompat(model)은 실행기에 전달되기 전에 해석된 모델에 동일한 xAI compat 패치를 적용합니다.
normalizeResolvedModel과
contributeResolvedModelCompat를 사용해 해당 compat 메타데이터를
core에 xAI 규칙을 하드코딩하는 대신 provider가 소유하도록 유지합니다.동일한 package-root 패턴은 다른 번들 provider에도 적용됩니다.@openclaw/openai-provider:api.ts는 provider builder, default-model 헬퍼, realtime provider builder를 export합니다@openclaw/openrouter-provider:api.ts는 provider builder와 온보딩/config 헬퍼를 export합니다
- 토큰 교환
- 커스텀 헤더
- 네이티브 전송 ID
- 사용량 및 과금
매 추론 호출 전에 토큰 교환이 필요한 provider의 경우:
사용 가능한 모든 provider hook
사용 가능한 모든 provider hook
OpenClaw는 다음 순서로 hook을 호출합니다. 대부분의 provider는 2~3개만 사용합니다.
런타임 fallback 참고 사항:
| # | Hook | 사용 시점 |
|---|---|---|
| 1 | catalog | 모델 카탈로그 또는 기본 baseUrl |
| 2 | applyConfigDefaults | config materialization 중 provider 소유 전역 기본값 |
| 3 | normalizeModelId | 조회 전 legacy/preview 모델 id alias 정리 |
| 4 | normalizeTransport | 일반 모델 조립 전 provider-family api / baseUrl 정리 |
| 5 | normalizeConfig | models.providers.<id> config 정규화 |
| 6 | applyNativeStreamingUsageCompat | config provider용 네이티브 streaming-usage compat 재작성 |
| 7 | resolveConfigApiKey | provider 소유 env-marker 인증 해석 |
| 8 | resolveSyntheticAuth | 로컬/self-hosted 또는 config 기반 synthetic auth |
| 9 | shouldDeferSyntheticProfileAuth | synthetic 저장 프로필 placeholder를 env/config 인증 뒤로 낮춤 |
| 10 | resolveDynamicModel | 임의의 업스트림 모델 ID 허용 |
| 11 | prepareDynamicModel | 해석 전 비동기 메타데이터 가져오기 |
| 12 | normalizeResolvedModel | 실행기 전 transport 재작성 |
-
normalizeConfig는 먼저 일치하는 provider를 확인한 다음, 실제로 config를 변경하는 hook 가능 provider 플러그인을 차례로 확인합니다. 어떤 provider hook도 지원되는 Google-family config 엔트리를 재작성하지 않으면, 번들 Google config normalizer가 여전히 적용됩니다. -
resolveConfigApiKey는 노출된 경우 provider hook을 사용합니다. 번들amazon-bedrock경로는 여기에서 AWS env-marker resolver도 내장하고 있지만, Bedrock 런타임 인증 자체는 여전히 AWS SDK 기본 체인을 사용합니다. | 13 |contributeResolvedModelCompat| 다른 호환 transport 뒤의 vendor 모델용 compat 플래그 | | 14 |capabilities| legacy 정적 capability bag; 호환성 전용 | | 15 |normalizeToolSchemas| 등록 전 provider 소유 tool-schema 정리 | | 16 |inspectToolSchemas| provider 소유 tool-schema 진단 | | 17 |resolveReasoningOutputMode| 태그형 vs 네이티브 reasoning-output 계약 | | 18 |prepareExtraParams| 기본 요청 params | | 19 |createStreamFn| 완전한 커스텀 StreamFn transport | | 20 |wrapStreamFn| 일반 스트림 경로의 커스텀 헤더/body wrapper | | 21 |resolveTransportTurnState| 네이티브 턴별 헤더/메타데이터 | | 22 |resolveWebSocketSessionPolicy| 네이티브 WS 세션 헤더/쿨다운 | | 23 |formatApiKey| 커스텀 런타임 토큰 형식 | | 24 |refreshOAuth| 커스텀 OAuth 새로 고침 | | 25 |buildAuthDoctorHint| 인증 복구 가이드 | | 26 |matchesContextOverflowError| provider 소유 overflow 감지 | | 27 |classifyFailoverReason| provider 소유 rate-limit/overload 분류 | | 28 |isCacheTtlEligible| 프롬프트 캐시 TTL 게이팅 | | 29 |buildMissingAuthMessage| 커스텀 missing-auth 힌트 | | 30 |suppressBuiltInModel| 오래된 업스트림 행 숨기기 | | 31 |augmentModelCatalog| synthetic forward-compat 행 | | 32 |isBinaryThinking| 바이너리 thinking on/off | | 33 |supportsXHighThinking|xhighreasoning 지원 | | 34 |resolveDefaultThinkingLevel| 기본/think정책 | | 35 |isModernModelRef| 라이브/스모크 모델 매칭 | | 36 |prepareRuntimeAuth| 추론 전 토큰 교환 | | 37 |resolveUsageAuth| 커스텀 사용량 자격 증명 파싱 | | 38 |fetchUsageSnapshot| 커스텀 사용량 엔드포인트 | | 39 |createEmbeddingProvider| memory/search용 provider 소유 embedding adapter | | 40 |buildReplayPolicy| 커스텀 대화 기록 replay/compaction 정책 | | 41 |sanitizeReplayHistory| 일반 정리 후 provider 전용 replay 재작성 | | 42 |validateReplayTurns| 임베디드 실행기 전 엄격한 replay-turn 검증 | | 43 |onModelSelected| 선택 후 콜백(예: telemetry) | 프롬프트 튜닝 참고:resolveSystemPromptContribution를 사용하면 provider가 모델 family에 대해 캐시 인식 system-prompt 가이드를 주입할 수 있습니다. 이 동작이 하나의 provider/모델 family에 속하고 안정적/동적 캐시 분리를 유지해야 한다면before_prompt_build보다 이것을 우선 사용하세요.
추가 기능 추가(선택 사항)
provider 플러그인은 텍스트 추론과 함께 speech, realtime transcription, realtime
voice, media understanding, image generation, video generation, web fetch,
web search도 등록할 수 있습니다.OpenClaw는 이를 hybrid-capability 플러그인으로 분류합니다. 이는
회사 플러그인(벤더당 하나의 플러그인)에 권장되는 패턴입니다. 자세한 내용은
Internals: Capability Ownership을 참조하세요.비디오 생성의 경우 위에 표시된 mode 인식 capability 형태를 우선 사용하세요.
generate, imageToVideo, videoToVideo를 사용해야 합니다. maxInputImages,
maxInputVideos, maxDurationSeconds 같은 평면 집계 필드만으로는
transform 모드 지원 또는 비활성화된 모드를 깔끔하게 알리기에 충분하지 않습니다.음악 생성 provider도 같은 패턴을 따라야 합니다.
프롬프트 전용 생성에는 generate, 참조 이미지 기반 생성에는 edit를 사용합니다.
maxInputImages,
supportsLyrics, supportsFormat 같은 평면 집계 필드만으로는 edit
지원을 알리기에 충분하지 않습니다. 명시적인 generate / edit 블록이 기대되는 계약입니다.ClawHub에 게시
Provider 플러그인은 다른 외부 코드 플러그인과 같은 방식으로 게시합니다.clawhub package publish를 사용해야 합니다.
파일 구조
Catalog order 참조
catalog.order는 내장 provider에 비해 catalog가 언제 병합되는지를 제어합니다.
| Order | 시점 | 사용 사례 |
|---|---|---|
simple | 첫 번째 패스 | 일반 API 키 provider |
profile | simple 이후 | 인증 profile에 의해 게이트되는 provider |
paired | profile 이후 | 여러 관련 엔트리를 합성 |
late | 마지막 패스 | 기존 provider 재정의(충돌 시 우선 적용) |
다음 단계
- Channel Plugins — 플러그인이 채널도 제공하는 경우
- SDK Runtime —
api.runtime헬퍼(TTS, 검색, subagent) - SDK Overview — 전체 하위 경로 import 참조
- Plugin Internals — hook 세부 사항과 번들 예시