@clavata/sdk
v0.4.1
Published
This directory contains the JS version of our SDK.
Readme
Clavata JavaScript SDK
This directory contains the Clavata JavaScript SDK with type definitions.
Getting started
Email [email protected] if you do not already have an API key/token.
Initialize the SDK to get started making requests to the Clavata API.
import Clavata from "@clavata/sdk";
// API key can be provided directly or via environment variable
const clavata = new Clavata({ apiKey: "<YOUR_CLAVATA_API_KEY>" } as Options);Configuration
The client constructor accepts the following options:
interface Options {
// Your API key. If not provided you _must_ then set CLAVATA_API_KEY as an environment variable
apiKey?: string;
// Optional
server?: string; // Server endpoint (default: "gateway.app.clavata.ai:443")
insecure?: boolean; // Use insecure connection. (default: false)
keepalive?: {
// Connection keepalive settings
timeout: number; // How long to wait for a response to a keepalive ping before considering the connection dead (in ms). (default: 10000)
permitWithoutCalls: boolean; // Allows keepalive pings to maintain idle connections. (default: true)
time: number; // How frequently to send keepalive pings to check if the connection is alive (in ms). (default: 10000)
};
maxMessageLength?: number; // Max message size (default: 100MB)
retryConfig:
| {
// Configuration for automatic retries. Will retry by default. Set to `false` to disable this. See https://grpc.io/docs/guides/retry for more info.
maxAttempts?: number; // Maximum number of retry attempts (default: 5)
initialBackoff?: string; // Initial backoff time in milliseconds (default: "1s")
maxBackoff?: string; // Maximum backoff time (default: "30s")
backoffMultiplier?: number; // Multiplier for backoff time after each retry (default: 2.0)
jitter?: number; // Jitter factor between 0 and 1 (default: 0.2, 0 = no jitter, 1 = full jitter)
}
| false;
}If neither an API key is provided to the constructor nor is a process.env.CLAVATA_API_KEY environment variable set then the constructor will throw an error.
RPC Methods
getJob(jobId: string): Promise<Job | undefined>
- Retrieves a job by its UUID.
listJobs(request: ListJobsRequest): Promise<ListJobsResponse>
- Lists jobs with filtering parameters.
createJob(request: CreateJobRequest): Promise<CreateJobResponse[]>
- Creates a new job with the provided content data and returns the id and status of the job that can be requested at a later point in time. If you need to await the result use
evaluateinstead.
evaluate(request: EvaluateRequest): Promise<AsyncIterable<EvaluateMessage | StreamError>>
- Evaluates each input and returns a stream of responses or errors. Order is not guaranteed, so using metadata or a contentHash is advised when sending multiple pieces to evaluate in a single call.
- Example:
const stream = clavata.evaluate({
contentData: [
{
metadata: { id: "1" },
content: { value: "Hello, world!", $case: "text" },
contentType: "text",
},
{
metadata: { id: "2" },
content: { value: Buffer.from("<BASE64_DATA>", "base64"), $case: "image" },
contentType: "image/png",
},
{
metadata: { id: "3" },
content: { value: "<IMAGE_URL>", $case: "imageUrl" },
contentType: "image/jpeg",
},
],
policyId: "00000000-0000-0000-0000-000000000000",
});
for await (const item of stream) {
if (item instanceof StreamError) throw item;
const { metadata, report } = item;
console.log({ id: metadata?.id, matches: report?.matches });
}Refusals
Under certain circumstances, the Clavata API will refuse to evaluate content as requested. There are only a few possible reasons for this:
- The content (image) matches a known hash in our CSAM database. This can be either an exact match or a perceptual hash match.
- The content (image) is in an unsupported format. Currently, Clavata supports
webp,pngandjpgimages. - The content was corrupt. Usually because the content was incomplete or the encoding (for images) was incorrect.
When a refusal occurs, a StreamError will be returned (for evaluate) or thrown (for createJob). You can check whether the error was caused by a refusal using the getRefusalReason() method on the StreamError type. If the error was not caused by a refusal, this method will return undefined. If the error is due to a refusal, a RefusalReason will be returned.
The RefusalReason type is a enum with strings matching one of:
"CSAM""UNSUPPORTED_IMAGE_FORMAT""INVALID_IMAGE"
There is also an "UNKNOWN" option, but this case indicates something went wrong decoding the "reason" information in the response.
import { RefusalReason } from "@clavata/sdk";
const stream = clavata.evaluate(...)
for await (const item of stream) {
if (item instanceof StreamError) {
const reason = item.getRefusalReason();
if (!reason) {
// Not a refusal, you can check the other possible identification methods like
if (item.isTransient()) {
// Transient error so we can retry
}
}
// It was a refusal, so we can use a switch statement to figure out why
switch (reason) {
case RefusalReason.CSAM:
// Handle CSAM appropriately
break;
case RefusalReason.UNSUPPORTED_IMAGE_FORMAT:
// Convert image and try again
break;
case RefusalReason.INVALID_IMAGE:
// data corruption, maybe try to re-download from CDN and try again?
break;
default:
// unknown reason for refusal
}
}
}Getting the Refusal Error
If you prefer, you can convert a StreamError into a RefusalError with the toRefusalError() method. Once again, if the error was not caused by a refusal, this method will return undefined. If, however, a refusal did occur the RefusalError type that is returned has the following interface that you can use to understand why:
interface RefusalError {
isCSAM(): boolean;
isUnsupportedImageFormat(): boolean;
isInvalidImage(): boolean;
isUnknown(): boolean;
getReason(): RefusalReason;
}
// So you can do this:
if (item instanceof StreamError) {
const refusalErr = item.toRefusalError();
if (refusalErr.isCSAM()) {
// Take action based on the content having been CSAM
}
}Which interface you use to determine the reason is up to you, they are functionally equivalent.
Refusals and createJob
When calling createJob, a promise is returned. If an error occurs, that error is automatically converted to a StreamError by the SDK and re-thrown. You can then catch the StreamError and check for refusals the same way.
Contributing
Update the version with npm version to the next SEMVER then run npm publish.
