Skip to content

v1.0.0 Release

Compare
Choose a tag to compare
@jhamon jhamon released this 07 Sep 15:15
· 169 commits to main since this release

This release adds a new module export, Pinecone, that is an all-new client for calling Pinecone from your TypeScript applications.

See the README docs and Migration guide to get started.

Features in this release

  • Simplified library initialization. Now you can simply new Pinecone() to make a client instance without the need for any awkward async initialization steps. The new client can also read the PINECONE_ENVIRONMENT and PINECONE_API_KEY environment variables in lieu of a config argument.
import { Pinecone, PineconeClient } from '@pinecone-database/pinecone'

const config = { apiKey: 'your-api-key', environment: 'your-environment' }

// Legacy client had this awkward 2-step init
const pineconeClient = new PineconeClient(); 
await pineconeClient.init(config);

// New client is a normal object with no extra steps needed
const pinecone = new Pinecone(config);
  • Simplified method signatures. The legacy client was generated using openapi and contained a lot of top-level keys in method parameters that were confusing and cumbersome to use. Now we have streamlined things across the board to eliminate these useless top-level keys.
// Old client
const pineconeClient = new PineconeClient(); 
await pineconeClient.init(config);
await pineconeClient.createIndex({ createRequest: { name: 'my-index', dimension: 1536 }})

// New client
const pinecone = new Pinecone()
await pinecone.createIndex({ name: 'my-index', dimension: 1536 })
  • Easily target namespaces. For those using paid indexes, namespaces are a useful way to organize your data but in the legacy client using them required passing the namespace with every request. That was error-prone and led to confusing results if the namespace param was ever accidentally omitted. Now you can specify namespace once to create a scoped client instance that will send all operations to the same namespace.
const vectors = [...] // Assume you have some embeddings to upsert
const queryVector = [...] // and also a query embedding

// The legacy PineconeClient required passing namespace in every method call. 
// This made the code verbose and error prone.
const pineconeClient = new PineconeClient();
await pineconeClient.init(config);
const index = pineconeClient.index('index-name') 
await index.upsert({ 
 upsertRequest: 
   { 
     vectors, 
     namespace: 'ns1' 
   }
})
const results = await index.query({ 
 queryRequest: { 
   topK: 2, 
   vector: queryVector, 
   namespace: 'ns1' // don't forget this, or else!
 }
})

// The new Pinecone client can create a scoped index client that accepts data 
// operations without the need to pass namespace with every method call.
const pinecone = new Pinecone();
const ns1 = pinecone.index('index-name').namespace('ns1'); 
await ns1.upsert(vectors)
const results2 = await ns1.query({ topK: 2, vector: queryVector })
  • Published TypeScript types with support for generics to enable proper typing of metadata. Say goodbye to awkward type casting every time you want to access information in metadata.
const pinecone = new Pinecone()

// User-defined type for metadata
type MovieMetadata = {
  title: string,
  genre: string,
  runtime: number
}

// You can now tell the client what type you expect metadata to have
// so you won't have to cast the type of query or fetch results.
const index = pinecone.index<MovieMetadata>('movie-embeddings')

const response = index.fetch(['1234'])
const movieRecord = response.records['1234']
if (movieRecord && movieRecord.metadata) {
  // Now typescript should no longer require any casting to interact with this metadata
  console.log(movieRecord.metadata.genre)
}

// And if you pass the wrong metadata into upsert you should now get typescript feedback
await index.upsert([{ 
  id: '2345', 
  values: [0.2, 0.3, 0.4], 
  metadata: { description: 'this prop not in MovieMetadata' } // should be ts error
}])
  • Runtime validations to give improved user feedback and stacktraces when incorrect parameters are passed to the library. These validations can be disabled if desired by setting PINECONE_DISABLE_RUNTIME_VALIDATIONS=true
> await pinecone.createIndex({ name: 'test-index' })
Uncaught:
PineconeArgumentError: The argument to createIndex must have required property: dimension.
    at /Users/jhamon/workspace/pinecone-ts-client/dist/validator.js:201:19
    at /Users/jhamon/workspace/pinecone-ts-client/dist/control/createIndex.js:64:21
    at step (/Users/jhamon/workspace/pinecone-ts-client/dist/control/createIndex.js:33:23)
    at Object.next (/Users/jhamon/workspace/pinecone-ts-client/dist/control/createIndex.js:14:53)
    at /Users/jhamon/workspace/pinecone-ts-client/dist/control/createIndex.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/jhamon/workspace/pinecone-ts-client/dist/control/createIndex.js:4:12)
    at Pinecone.createIndex (/Users/jhamon/workspace/pinecone-ts-client/dist/control/createIndex.js:59:40)
    at REPL18:1:48
  • Backwards compatible. Since all these changes are implemented as part of a new Pinecone client export, if you have production code using the legacy PineconeClient export you can continue to use it without changes for now. But we hope you will gradually migrate to the Pinecone client because the PineconeClient will be removed in a future release.
  • Migration to the Apache 2 open source license. This library was previously release under another permissive open source license (MIT license) so this will be a distinction without a difference for most users. But this is the first step we're taking toward standardizing all of our published client code on one open source license.
  • Other convenience methods and improvements:
    • Delete more easily using deleteOne, deleteMany, and deleteAll.
    • Need to upsert data immediately after creating an index? The waitUntilReady parameter tells the create method not to resolve the promise until an index is ready to receive data. await pinecone.createIndex({ name: 'name', dimension: 10, waitUntilReady: true })

Documentation and Examples