add-provider
Use when adding a new LLM provider to ra.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when adding a new LLM provider to ra.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
System design and architecture decisions. Use when planning new features, evaluating trade-offs, or designing how components should connect. Proposes 2-3 approaches and recommends one.
Smart commit workflow. Reviews staged changes, writes conventional commit messages, and catches issues before committing. Use when ready to commit work.
Quality review of completed work. Use after making changes and before claiming completion. Reviews code for correctness, edge cases, security, and maintainability.
Systematic debugging workflow. Use when diagnosing bugs, test failures, or unexpected behavior. Follows a rigorous reproduce → isolate → hypothesize → fix → verify cycle.
Systematic multi-agent research. Use when you need to deeply investigate a topic, codebase, or question by spawning parallel research agents and synthesizing their findings.
Deep code explanation. Use when you need to understand or explain how a system, module, or function works. Traces data flow, maps dependencies, and explains design decisions.
| name | add-provider |
| description | Use when adding a new LLM provider to ra. |
See src/providers/CLAUDE.md for the adapter pattern and StreamChunk contract. Use anthropic.ts as a template.
src/providers/<name>.ts — Provider class:import type { IProvider, ChatRequest, ChatResponse, StreamChunk } from './types'
export interface XProviderOptions {
apiKey: string
}
export class XProvider implements IProvider {
readonly name = 'x'
private client: SdkClient
constructor(options: XProviderOptions) {
this.client = new SdkClient({ apiKey: options.apiKey })
}
buildParams(request: ChatRequest) {
return {
model: request.model,
messages: this.mapMessages(request.messages),
...(request.tools?.length && { tools: this.mapTools(request.tools) }),
...(request.thinking && { /* provider-specific thinking config */ }),
}
}
async chat(request: ChatRequest): Promise<ChatResponse> { /* ... */ }
async *stream(request: ChatRequest): AsyncIterable<StreamChunk> {
// Must yield: text, tool_call_start, tool_call_delta*, tool_call_end, done
// done chunk MUST include usage if available
}
private mapMessages(messages: IMessage[]) { /* ra → SDK */ }
private mapTools(tools: ITool[]) { /* ra → SDK */ }
private mapResponseToMessage(response: SdkResponse): IMessage { /* SDK → ra */ }
}
src/providers/registry.ts — Add to ProviderOptionsMap, import class, add case to createProvider()
src/config/types.ts — Add to ProviderName union and providers field in RaConfig
src/config/defaults.ts — Add default options under providers
src/config/index.ts — Add env var mapping (RA_<NAME>_API_KEY)
tests/providers/<name>.test.ts — Mock the SDK client, test buildParams(), stream() chunk sequence
Verify: bun tsc → bun test → bun run ra --provider <name> --model <model> "Hello"
stream() is primary — the loop always uses streaming. chat() is secondary.stream() must yield a { type: 'done' } chunk at the end, even if the SDK doesn't emit one.buildParams() should be a separate method so tests can inspect requests without mocking the SDK....(x && { key: x }).