@clervo/sdk
Advanced tools
| export declare const CLERVO_CONTRACT_VERSION: '2026-07-29.1'; | ||
| export declare const CLERVO_RELEASE_CANDIDATE_ID: 'clervo-private-core-2026-08-02.2'; | ||
| export declare const CLERVO_RELEASE_CANDIDATE_INTERFACE_HASH: 'sha256:1b32a86f5725499f90d3e2f167f4432563f67bac477a3ca0e552f0958bf26622'; | ||
| export type ClervoProductId = 'search.web' | 'search.answer'; | ||
| export type ClervoExecutionMode = 'preview' | 'challenge'; | ||
| export interface ClervoSearchRequest { | ||
| query: string; | ||
| maxResults?: number; | ||
| language?: string; | ||
| region?: string; | ||
| } | ||
| export interface ClervoSearchResult { | ||
| contractVersion: typeof CLERVO_CONTRACT_VERSION; | ||
| operationId: string; | ||
| operation: 'search.query'; | ||
| productId: ClervoProductId; | ||
| state: 'RECEIPTED'; | ||
| replayed: boolean; | ||
| fundingMode: 'free' | 'paid'; | ||
| requestHash: string; | ||
| output: { | ||
| searchResponse: Record<string, unknown>; | ||
| synthesisReport?: Record<string, unknown>; | ||
| }; | ||
| receipt?: unknown; | ||
| } | ||
| export interface ClervoProblem { | ||
| type?: string; | ||
| title?: string; | ||
| status?: number; | ||
| detail?: string; | ||
| instance?: string; | ||
| code?: string; | ||
| operationId?: string; | ||
| retryable?: boolean; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ClervoRequestOptions { | ||
| idempotencyKey?: string; | ||
| mode?: ClervoExecutionMode; | ||
| signal?: AbortSignal; | ||
| } | ||
| export interface ClervoClientOptions { | ||
| baseUrl: string; | ||
| fetch?: typeof fetch; | ||
| maxResponseBytes?: number; | ||
| } | ||
| export type ClervoRecoveryCode = 'insufficient_funds' | 'wrong_network_or_asset' | 'expired_quote' | 'rejected' | 'timeout' | 'unknown_settlement'; | ||
| export interface ClervoRecoveryAction { | ||
| code: ClervoRecoveryCode; | ||
| action: string; | ||
| retry: 'after_action' | 'prohibited_until_reconciled'; | ||
| } | ||
| export declare function recoveryActionFor(value: unknown): Readonly<ClervoRecoveryAction> | undefined; | ||
| export declare class ClervoError extends Error { | ||
| constructor(message: string, options?: ErrorOptions); | ||
| } | ||
| export declare class ClervoTransportError extends ClervoError { | ||
| } | ||
| export declare class ClervoProtocolError extends ClervoError { | ||
| } | ||
| export declare class ClervoProblemError extends ClervoError { | ||
| readonly status: number; | ||
| readonly problem: ClervoProblem; | ||
| constructor(status: number, problem: ClervoProblem); | ||
| } | ||
| export declare class ClervoPaymentRequiredError extends ClervoProblemError { | ||
| readonly paymentRequired: string | null; | ||
| constructor(problem: ClervoProblem, paymentRequired: string | null); | ||
| } | ||
| export declare class ClervoClient { | ||
| #private; | ||
| readonly search: { | ||
| web: (request: ClervoSearchRequest, options?: ClervoRequestOptions) => Promise<ClervoSearchResult>; | ||
| answer: (request: ClervoSearchRequest, options?: ClervoRequestOptions) => Promise<ClervoSearchResult>; | ||
| }; | ||
| constructor(options: ClervoClientOptions); | ||
| } |
+234
| export const CLERVO_CONTRACT_VERSION = '2026-07-29.1'; | ||
| export const CLERVO_RELEASE_CANDIDATE_ID = 'clervo-private-core-2026-08-02.2'; | ||
| export const CLERVO_RELEASE_CANDIDATE_INTERFACE_HASH = 'sha256:1b32a86f5725499f90d3e2f167f4432563f67bac477a3ca0e552f0958bf26622'; | ||
| const recoveryActions = Object.freeze([ | ||
| Object.freeze({ | ||
| code: 'insufficient_funds', | ||
| problemCodes: Object.freeze(['insufficient_funds']), | ||
| action: 'Add enough of the quoted asset on the quoted network, then request a fresh quote.', | ||
| retry: 'after_action', | ||
| }), | ||
| Object.freeze({ | ||
| code: 'wrong_network_or_asset', | ||
| problemCodes: Object.freeze(['wrong_network', 'wrong_asset', 'unsupported_network', 'unsupported_asset']), | ||
| action: "Switch to the quote's exact network and asset, then request a fresh quote.", | ||
| retry: 'after_action', | ||
| }), | ||
| Object.freeze({ | ||
| code: 'expired_quote', | ||
| problemCodes: Object.freeze(['quote_expired', 'expired_quote']), | ||
| action: 'Request a fresh quote and never reuse the expired authorization.', | ||
| retry: 'after_action', | ||
| }), | ||
| Object.freeze({ | ||
| code: 'rejected', | ||
| problemCodes: Object.freeze(['authorization_rejected', 'payment_rejected', 'user_rejected']), | ||
| action: 'Review the maximum charge and approve again only if you still intend to pay.', | ||
| retry: 'after_action', | ||
| }), | ||
| Object.freeze({ | ||
| code: 'timeout', | ||
| problemCodes: Object.freeze(['authorization_timeout', 'payment_timeout']), | ||
| action: 'Reconcile the existing idempotency key before deciding whether to retry.', | ||
| retry: 'prohibited_until_reconciled', | ||
| }), | ||
| Object.freeze({ | ||
| code: 'unknown_settlement', | ||
| problemCodes: Object.freeze(['settlement_unknown', 'unknown_settlement']), | ||
| action: 'Reconcile the existing operation and do not authorize or retry until settlement is definitive.', | ||
| retry: 'prohibited_until_reconciled', | ||
| }), | ||
| ]); | ||
| export function recoveryActionFor(value) { | ||
| const problemCode = value instanceof ClervoProblemError && typeof value.problem.code === 'string' | ||
| ? value.problem.code | ||
| : typeof value === 'string' ? value : undefined; | ||
| if (problemCode === undefined) | ||
| return undefined; | ||
| const recovery = recoveryActions.find(({ problemCodes }) => problemCodes.includes(problemCode)); | ||
| if (recovery === undefined) | ||
| return undefined; | ||
| return Object.freeze({ code: recovery.code, action: recovery.action, retry: recovery.retry }); | ||
| } | ||
| function assertBaseUrl(value) { | ||
| let parsed; | ||
| try { | ||
| parsed = new URL(value); | ||
| } | ||
| catch { | ||
| throw new TypeError('invalid_clervo_base_url'); | ||
| } | ||
| const loopback = parsed.hostname === 'localhost' | ||
| || parsed.hostname === '127.0.0.1' | ||
| || parsed.hostname === '[::1]'; | ||
| if (parsed.protocol !== 'https:' && !(parsed.protocol === 'http:' && loopback)) | ||
| throw new TypeError('unsafe_clervo_base_url'); | ||
| if (parsed.username || parsed.password || parsed.search || parsed.hash) | ||
| throw new TypeError('invalid_clervo_base_url'); | ||
| return parsed.toString().replace(/\/+$/u, ''); | ||
| } | ||
| function assertSearchRequest(request) { | ||
| if (request === null || typeof request !== 'object' || Array.isArray(request)) | ||
| throw new TypeError('invalid_search_request'); | ||
| if (typeof request.query !== 'string' | ||
| || request.query.trim().length < 1 | ||
| || request.query.trim().length > 2_000 | ||
| || /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/u.test(request.query)) | ||
| throw new TypeError('invalid_search_query'); | ||
| if (request.maxResults !== undefined && (!Number.isInteger(request.maxResults) || request.maxResults < 1 || request.maxResults > 10)) | ||
| throw new TypeError('invalid_search_max_results'); | ||
| if (request.language !== undefined && (typeof request.language !== 'string' || !/^[a-z]{2,3}$/u.test(request.language))) | ||
| throw new TypeError('invalid_search_language'); | ||
| if (request.region !== undefined && (typeof request.region !== 'string' || !/^[A-Z]{2}$/u.test(request.region))) | ||
| throw new TypeError('invalid_search_region'); | ||
| } | ||
| function idempotencyKey() { | ||
| return `clervo_${crypto.randomUUID()}`; | ||
| } | ||
| async function readResponseText(response, maximumBytes) { | ||
| const declared = Number(response.headers.get('content-length')); | ||
| if (Number.isFinite(declared) && declared > maximumBytes) | ||
| throw new ClervoProtocolError('clervo_response_too_large'); | ||
| if (response.body === null) | ||
| return ''; | ||
| const reader = response.body.getReader(); | ||
| const decoder = new TextDecoder(); | ||
| const parts = []; | ||
| let bytes = 0; | ||
| for (;;) { | ||
| const { done, value } = await reader.read(); | ||
| if (done) | ||
| break; | ||
| bytes += value.byteLength; | ||
| if (bytes > maximumBytes) { | ||
| await reader.cancel(); | ||
| throw new ClervoProtocolError('clervo_response_too_large'); | ||
| } | ||
| parts.push(decoder.decode(value, { stream: true })); | ||
| } | ||
| parts.push(decoder.decode()); | ||
| return parts.join(''); | ||
| } | ||
| function parseJsonObject(text) { | ||
| let value; | ||
| try { | ||
| value = JSON.parse(text); | ||
| } | ||
| catch { | ||
| throw new ClervoProtocolError('clervo_response_invalid_json'); | ||
| } | ||
| if (value === null || typeof value !== 'object' || Array.isArray(value)) | ||
| throw new ClervoProtocolError('clervo_response_invalid_shape'); | ||
| return value; | ||
| } | ||
| function validateResult(value, productId, fundingMode) { | ||
| if (value.contractVersion !== CLERVO_CONTRACT_VERSION | ||
| || value.operation !== 'search.query' | ||
| || value.productId !== productId | ||
| || value.state !== 'RECEIPTED' | ||
| || value.fundingMode !== fundingMode | ||
| || typeof value.operationId !== 'string' | ||
| || typeof value.requestHash !== 'string' | ||
| || typeof value.replayed !== 'boolean' | ||
| || value.output === null | ||
| || typeof value.output !== 'object' | ||
| || Array.isArray(value.output)) | ||
| throw new ClervoProtocolError('clervo_result_contract_mismatch'); | ||
| return value; | ||
| } | ||
| export class ClervoError extends Error { | ||
| constructor(message, options) { | ||
| super(message, options); | ||
| this.name = new.target.name; | ||
| } | ||
| } | ||
| export class ClervoTransportError extends ClervoError { | ||
| } | ||
| export class ClervoProtocolError extends ClervoError { | ||
| } | ||
| export class ClervoProblemError extends ClervoError { | ||
| status; | ||
| problem; | ||
| constructor(status, problem) { | ||
| super(typeof problem.code === 'string' ? problem.code : `clervo_http_${status}`); | ||
| this.status = status; | ||
| this.problem = problem; | ||
| } | ||
| } | ||
| export class ClervoPaymentRequiredError extends ClervoProblemError { | ||
| paymentRequired; | ||
| constructor(problem, paymentRequired) { | ||
| super(402, problem); | ||
| this.paymentRequired = paymentRequired; | ||
| } | ||
| } | ||
| export class ClervoClient { | ||
| #baseUrl; | ||
| #fetch; | ||
| #maxResponseBytes; | ||
| search; | ||
| constructor(options) { | ||
| if (options === null || typeof options !== 'object') | ||
| throw new TypeError('invalid_clervo_client_options'); | ||
| this.#baseUrl = assertBaseUrl(options.baseUrl); | ||
| this.#fetch = options.fetch ?? globalThis.fetch; | ||
| if (typeof this.#fetch !== 'function') | ||
| throw new TypeError('clervo_fetch_unavailable'); | ||
| this.#maxResponseBytes = options.maxResponseBytes ?? 2_097_152; | ||
| if (!Number.isInteger(this.#maxResponseBytes) || this.#maxResponseBytes < 1_024 || this.#maxResponseBytes > 16_777_216) | ||
| throw new TypeError('invalid_clervo_response_limit'); | ||
| this.search = Object.freeze({ | ||
| web: (request, requestOptions) => this.#execute('search.web', request, requestOptions), | ||
| answer: (request, requestOptions) => this.#execute('search.answer', request, requestOptions), | ||
| }); | ||
| } | ||
| async #execute(productId, request, options = {}) { | ||
| assertSearchRequest(request); | ||
| if (options === null || typeof options !== 'object') | ||
| throw new TypeError('invalid_clervo_request_options'); | ||
| const mode = options.mode ?? 'preview'; | ||
| if (mode !== 'preview' && mode !== 'challenge') | ||
| throw new TypeError('invalid_clervo_execution_mode'); | ||
| const fundingMode = mode === 'preview' ? 'free' : 'paid'; | ||
| const target = mode === 'preview' ? '/v1/search/free' : '/v1/search/paid'; | ||
| const requestIdempotencyKey = options.idempotencyKey ?? idempotencyKey(); | ||
| if (!/^[\x21-\x7E]{8,128}$/u.test(requestIdempotencyKey)) | ||
| throw new TypeError('invalid_idempotency_key'); | ||
| const body = { | ||
| query: request.query.trim(), | ||
| ...(request.maxResults === undefined ? {} : { maxResults: request.maxResults }), | ||
| synthesize: productId === 'search.answer', | ||
| ...(request.language === undefined ? {} : { language: request.language }), | ||
| ...(request.region === undefined ? {} : { region: request.region }), | ||
| }; | ||
| let response; | ||
| try { | ||
| response = await this.#fetch(`${this.#baseUrl}${target}`, { | ||
| method: 'POST', | ||
| headers: { | ||
| accept: 'application/json, application/problem+json', | ||
| 'content-type': 'application/json', | ||
| 'idempotency-key': requestIdempotencyKey, | ||
| 'x-clervo-client': '@clervo/sdk/0.3.0', | ||
| }, | ||
| body: JSON.stringify(body), | ||
| redirect: 'error', | ||
| ...(options.signal === undefined ? {} : { signal: options.signal }), | ||
| }); | ||
| } | ||
| catch (error) { | ||
| throw new ClervoTransportError('clervo_transport_failed', { cause: error }); | ||
| } | ||
| const text = await readResponseText(response, this.#maxResponseBytes); | ||
| const contentType = response.headers.get('content-type')?.split(';', 1)[0]?.trim().toLowerCase(); | ||
| if (contentType !== undefined && contentType !== 'application/json' && contentType !== 'application/problem+json') | ||
| throw new ClervoProtocolError('clervo_response_unsupported_media_type'); | ||
| const value = parseJsonObject(text); | ||
| if (response.status === 402) | ||
| throw new ClervoPaymentRequiredError(value, response.headers.get('payment-required')); | ||
| if (!response.ok) | ||
| throw new ClervoProblemError(response.status, value); | ||
| return validateResult(value, productId, fundingMode); | ||
| } | ||
| } | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} |
+42
-8
| { | ||
| "name": "@clervo/sdk", | ||
| "version": "0.2.0", | ||
| "description": "Clervo x402 Gateway SDK — 23 AI models, 8 free. Pay per call in USDC.", | ||
| "version": "0.3.0", | ||
| "description": "Typed Clervo client generated from the frozen distribution candidate.", | ||
| "license": "UNLICENSED", | ||
| "type": "module", | ||
| "main": "./src/index.js", | ||
| "types": "./src/index.d.ts", | ||
| "keywords": ["clervo", "x402", "ai", "claude", "gpt", "deepseek", "llm", "usdc", "solana", "openai-compatible"], | ||
| "license": "MIT", | ||
| "engines": { "node": ">=18" }, | ||
| "files": ["src/", "README.md"] | ||
| "sideEffects": false, | ||
| "keywords": [ | ||
| "clervo", | ||
| "agent", | ||
| "search", | ||
| "sdk" | ||
| ], | ||
| "homepage": "https://clervo.dev/docs/typescript", | ||
| "bugs": { | ||
| "url": "https://github.com/clervo/clervo/issues" | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/clervo/clervo.git", | ||
| "directory": "packages/sdk-typescript" | ||
| }, | ||
| "engines": { | ||
| "node": ">=20" | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "README.md" | ||
| ], | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/index.d.ts", | ||
| "import": "./dist/index.js" | ||
| } | ||
| }, | ||
| "main": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "scripts": { | ||
| "build": "tsc --project tsconfig.json", | ||
| "prepack": "npm run build" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public", | ||
| "provenance": true | ||
| } | ||
| } |
+23
-108
@@ -1,121 +0,36 @@ | ||
| # @clervo/sdk | ||
| # `@clervo/sdk` | ||
| TypeScript/JavaScript SDK for the [Clervo x402 Gateway](https://api.clervo.dev). | ||
| Typed client for Clervo's frozen distribution candidate. | ||
| 23 AI models. 8 free. Pay per call in USDC on Solana. No API keys. | ||
| Current scope is deliberately narrow: | ||
| ## Install | ||
| - `search.web` and `search.answer`; | ||
| - repository-local preview execution; | ||
| - typed non-payable `402` challenges; | ||
| - idempotency and request cancellation; | ||
| - no wallet, signer, payment retry, or public-service assumption. | ||
| ```bash | ||
| npm install @clervo/sdk | ||
| ``` | ||
| The client requires an explicit `baseUrl` because no public API deployment is | ||
| currently verified. | ||
| ## Quick start | ||
| ```ts | ||
| import { ClervoClient } from '@clervo/sdk'; | ||
| ```typescript | ||
| import { Clervo } from '@clervo/sdk'; | ||
| const clervo = new Clervo(); | ||
| // Free call — no wallet needed | ||
| const response = await clervo.chat('groq/llama-3.1-8b-instant', 'Explain recursion in 2 sentences'); | ||
| console.log(response); | ||
| // List all models | ||
| const models = await clervo.models(); | ||
| const free = models.filter(m => m.lifecycle === 'free_beta'); | ||
| console.log(`${free.length} free models available`); | ||
| const clervo = new ClervoClient({ baseUrl: 'http://127.0.0.1:8080' }); | ||
| const result = await clervo.search.web({ query: 'payment idempotency' }); | ||
| ``` | ||
| ## Free models | ||
| `search.answer` sets synthesis explicitly. Callers cannot silently change the | ||
| product identity through the request body. | ||
| No payment, no wallet, no signup: | ||
| Known future payment failures can be reduced to one bounded next action without | ||
| triggering a payment or retry: | ||
| | Model | Speed | Best for | | ||
| |-------|-------|----------| | ||
| | `groq/llama-3.1-8b-instant` | 170ms | Fast responses | | ||
| | `groq/llama-3.3-70b` | ~800ms | Strong general | | ||
| | `sambanova/deepseek-v3.2` | 1.6s | Reasoning | | ||
| | `sambanova/llama-3.3-70b` | 1.5s | General | | ||
| | `hcn/qwen3.6-35b` | 0.9s | Fast small | | ||
| | `hcn/step-3.7-flash` | 3s | Reasoning | | ||
| | `hcn/deepseek-v4-pro` | 9s | Deep reasoning | | ||
| | `hcn/auto` | 3s | Auto-routed | | ||
| ```ts | ||
| import { recoveryActionFor } from '@clervo/sdk'; | ||
| ## Paid models (10-20% cheaper than BlockRun) | ||
| Fund a Solana wallet with USDC. x402 protocol handles payment automatically. | ||
| | Model | Price/req | | ||
| |-------|-----------| | ||
| | `tongkhokr/claude-haiku-4.5` | $0.002 | | ||
| | `tongkhokr/claude-sonnet-5` | $0.015 | | ||
| | `tongkhokr/claude-opus-5` | $0.084 | | ||
| | `quickai/gpt-5.4-mini` | $0.005 | | ||
| | `quickai/gpt-5.5` | $0.035 | | ||
| ## API | ||
| ### `new Clervo(options?)` | ||
| | Option | Default | Description | | ||
| |--------|---------|-------------| | ||
| | `apiUrl` | `https://api.clervo.dev` | API base URL | | ||
| ### `clervo.chat(model, message, options?)` | ||
| Simple chat. Returns the text response. | ||
| ```typescript | ||
| const text = await clervo.chat('groq/llama-3.1-8b-instant', 'Hello!'); | ||
| const recovery = recoveryActionFor(error); | ||
| ``` | ||
| ### `clervo.chatCompletion(model, messages, options?)` | ||
| Full OpenAI-compatible chat completion. | ||
| ```typescript | ||
| const result = await clervo.chatCompletion('sambanova/deepseek-v3.2', [ | ||
| { role: 'system', content: 'You are helpful.' }, | ||
| { role: 'user', content: 'What is 2+2?' } | ||
| ]); | ||
| console.log(result.choices[0].message.content); | ||
| console.log(result.usage); | ||
| ``` | ||
| ### `clervo.models()` | ||
| List all available models. | ||
| ### `clervo.freeModels()` | ||
| List only free models. | ||
| ### `clervo.operation(operationId)` | ||
| Look up an operation by ID (from `_operationId` on completion results). | ||
| ## OpenAI drop-in replacement | ||
| Since Clervo is OpenAI-compatible, you can also use the OpenAI SDK: | ||
| ```typescript | ||
| import OpenAI from 'openai'; | ||
| const client = new OpenAI({ | ||
| baseURL: 'https://api.clervo.dev/v1', | ||
| apiKey: 'unused', // no key needed for free models | ||
| }); | ||
| const response = await client.chat.completions.create({ | ||
| model: 'groq/llama-3.1-8b-instant', | ||
| messages: [{ role: 'user', content: 'Hello!' }], | ||
| }); | ||
| ``` | ||
| ## Links | ||
| - API: https://api.clervo.dev | ||
| - Models: https://api.clervo.dev/v1/models | ||
| - Quickstart: https://api.clervo.dev/quickstart.md | ||
| - OpenAPI: https://api.clervo.dev/openapi.json | ||
| Unknown settlement and payment-timeout actions prohibit retry until the | ||
| existing idempotency key is reconciled. |
| export interface ClervoOptions { | ||
| apiUrl?: string; | ||
| } | ||
| export interface ChatOptions { | ||
| system?: string; | ||
| maxTokens?: number; | ||
| } | ||
| export interface CompletionOptions { | ||
| maxTokens?: number; | ||
| responseFormat?: Record<string, unknown>; | ||
| } | ||
| export interface Message { | ||
| role: 'system' | 'user' | 'assistant'; | ||
| content: string; | ||
| } | ||
| export interface ChatCompletion { | ||
| id: string; | ||
| object: string; | ||
| model: string; | ||
| choices: Array<{ | ||
| index: number; | ||
| message: { role: string; content: string }; | ||
| finish_reason: string | null; | ||
| }>; | ||
| usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number }; | ||
| _operationId?: string; | ||
| _replay?: boolean; | ||
| } | ||
| export interface Model { | ||
| id: string; | ||
| object: string; | ||
| owned_by: string; | ||
| name: string; | ||
| description: string; | ||
| lifecycle: string; | ||
| callable: boolean; | ||
| purchasable: boolean; | ||
| capabilities: string[]; | ||
| funding: { mode: string } | null; | ||
| pricing: Record<string, unknown> | null; | ||
| } | ||
| export declare class Clervo { | ||
| constructor(options?: ClervoOptions); | ||
| chat(model: string, message: string, options?: ChatOptions): Promise<string>; | ||
| chatCompletion(model: string, messages: Message[], options?: CompletionOptions): Promise<ChatCompletion>; | ||
| models(): Promise<Model[]>; | ||
| freeModels(): Promise<Model[]>; | ||
| operation(operationId: string): Promise<Record<string, unknown> | null>; | ||
| } | ||
| export default Clervo; |
-194
| /** | ||
| * @clervo/sdk — TypeScript/JavaScript SDK for Clervo x402 Gateway | ||
| * | ||
| * Usage: | ||
| * import { Clervo } from '@clervo/sdk'; | ||
| * const ai = new Clervo(); | ||
| * | ||
| * // Chat (free models — no payment needed) | ||
| * const text = await ai.chat('groq/llama-3.1-8b-instant', 'Hello!'); | ||
| * | ||
| * // Search the web (free) | ||
| * const results = await ai.search('x402 protocol'); | ||
| * | ||
| * // Scrape a URL to markdown (free) | ||
| * const markdown = await ai.scrape('https://example.com'); | ||
| * | ||
| * // List all models | ||
| * const models = await ai.models(); | ||
| */ | ||
| import { randomUUID } from 'node:crypto'; | ||
| const DEFAULT_API = 'https://api.clervo.dev'; | ||
| export class Clervo { | ||
| #apiUrl; | ||
| #defaultModel; | ||
| #maxRetries; | ||
| /** | ||
| * @param {object} [options] | ||
| * @param {string} [options.apiUrl] - API base URL (default: https://api.clervo.dev) | ||
| * @param {string} [options.defaultModel] - Default model for chat (default: groq/llama-3.1-8b-instant) | ||
| * @param {number} [options.maxRetries] - Max retries on 503 (default: 2) | ||
| */ | ||
| constructor({ apiUrl, defaultModel, maxRetries } = {}) { | ||
| this.#apiUrl = apiUrl || process.env.CLERVO_API_URL || DEFAULT_API; | ||
| this.#defaultModel = defaultModel || 'groq/llama-3.1-8b-instant'; | ||
| this.#maxRetries = maxRetries ?? 2; | ||
| } | ||
| /** | ||
| * Simple chat — returns the text response. | ||
| * @param {string} modelOrMessage - Model ID, or message if using default model | ||
| * @param {string} [message] - User message (if first arg is model) | ||
| * @param {object} [options] | ||
| * @returns {Promise<string>} The assistant's text response | ||
| */ | ||
| async chat(modelOrMessage, message, { system, maxTokens = 1024, json = false } = {}) { | ||
| // Allow shorthand: ai.chat('Hello') uses default model | ||
| let model, userMessage; | ||
| if (message === undefined) { | ||
| model = this.#defaultModel; | ||
| userMessage = modelOrMessage; | ||
| } else { | ||
| model = modelOrMessage; | ||
| userMessage = message; | ||
| } | ||
| const result = await this.chatCompletion(model, [ | ||
| ...(system ? [{ role: 'system', content: system }] : []), | ||
| { role: 'user', content: userMessage }, | ||
| ], { maxTokens, responseFormat: json ? { type: 'json_object' } : undefined }); | ||
| return result.choices[0]?.message?.content || ''; | ||
| } | ||
| /** | ||
| * Full OpenAI-compatible chat completion. | ||
| * @param {string} model - Model ID | ||
| * @param {Array} messages - OpenAI-format messages | ||
| * @param {object} [options] | ||
| * @returns {Promise<object>} Full completion response with usage, operationId | ||
| */ | ||
| async chatCompletion(model, messages, { maxTokens = 1024, responseFormat } = {}) { | ||
| const body = { | ||
| model, | ||
| messages, | ||
| max_completion_tokens: maxTokens, | ||
| ...(responseFormat ? { response_format: responseFormat } : {}), | ||
| }; | ||
| const result = await this.#request('POST', '/v1/chat/completions', body, { | ||
| headers: { 'idempotency-key': randomUUID() }, | ||
| }); | ||
| return result; | ||
| } | ||
| /** | ||
| * Web search — returns structured results. | ||
| * @param {string} query - Search query | ||
| * @param {object} [options] | ||
| * @param {number} [options.maxResults=5] - Number of results (1-10) | ||
| * @returns {Promise<Array<{title: string, url: string, snippet: string}>>} | ||
| */ | ||
| async search(query, { maxResults = 5 } = {}) { | ||
| const result = await this.#request('POST', '/v1/search', { query, max_results: maxResults }); | ||
| return result.results || []; | ||
| } | ||
| /** | ||
| * Scrape URL to markdown. | ||
| * @param {string} url - URL to scrape | ||
| * @returns {Promise<string>} Page content as markdown | ||
| */ | ||
| async scrape(url) { | ||
| const result = await this.#request('POST', '/v1/scrape', { url }); | ||
| return result.content || ''; | ||
| } | ||
| /** | ||
| * List available models. | ||
| * @returns {Promise<Array>} All models with metadata | ||
| */ | ||
| async models() { | ||
| const r = await fetch(`${this.#apiUrl}/v1/models`); | ||
| const j = await r.json(); | ||
| return j.data || []; | ||
| } | ||
| /** | ||
| * Get free models only. | ||
| * @returns {Promise<Array>} Free models (no payment needed) | ||
| */ | ||
| async freeModels() { | ||
| const all = await this.models(); | ||
| return all.filter(m => m.lifecycle === 'free_beta'); | ||
| } | ||
| /** | ||
| * Get paid models only. | ||
| * @returns {Promise<Array>} Paid models with pricing | ||
| */ | ||
| async paidModels() { | ||
| const all = await this.models(); | ||
| return all.filter(m => m.lifecycle === 'paid_beta'); | ||
| } | ||
| /** | ||
| * Get operation status/receipt. | ||
| * @param {string} operationId - Operation ID from x-clervo-operation-id header | ||
| * @returns {Promise<object|null>} | ||
| */ | ||
| async operation(operationId) { | ||
| const r = await fetch(`${this.#apiUrl}/v1/operations/${operationId}`); | ||
| if (r.status === 404) return null; | ||
| return r.json(); | ||
| } | ||
| /** | ||
| * Internal request helper with retries. | ||
| */ | ||
| async #request(method, path, body, { headers = {} } = {}) { | ||
| let lastError; | ||
| for (let attempt = 0; attempt <= this.#maxRetries; attempt++) { | ||
| if (attempt > 0) await new Promise(r => setTimeout(r, 1000 * attempt)); | ||
| const r = await fetch(`${this.#apiUrl}${path}`, { | ||
| method, | ||
| headers: { 'content-type': 'application/json', ...headers }, | ||
| body: JSON.stringify(body), | ||
| }); | ||
| if (r.status === 402) { | ||
| const err = new Error(`Payment required. Use a free model or fund a wallet with USDC on Base.`); | ||
| err.code = 'PAYMENT_REQUIRED'; | ||
| err.status = 402; | ||
| throw err; | ||
| } | ||
| if (r.status === 503 && attempt < this.#maxRetries) { | ||
| lastError = new Error('Service temporarily unavailable'); | ||
| continue; | ||
| } | ||
| if (r.status !== 200) { | ||
| const j = await r.json().catch(() => ({})); | ||
| const err = new Error(j.error?.message || j.message || `API error: ${r.status}`); | ||
| err.code = j.error?.code || 'API_ERROR'; | ||
| err.status = r.status; | ||
| throw err; | ||
| } | ||
| const result = await r.json(); | ||
| result._operationId = r.headers.get('x-clervo-operation-id') || undefined; | ||
| result._replay = r.headers.get('x-idempotent-replay') === 'true'; | ||
| return result; | ||
| } | ||
| throw lastError; | ||
| } | ||
| } | ||
| export default Clervo; |
Explicitly Unlicensed Item
LicenseSomething was found which is explicitly marked as unlicensed.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Misc. License Issues
LicenseA package's licensing information has fine-grained problems.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
No website
QualityPackage does not have a website.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
24654
126.87%5
25%311
40.72%1
-50%0
-100%2
-33.33%1
-66.67%1
Infinity%1
Infinity%0
-100%37
-69.67%9
200%