-
Notifications
You must be signed in to change notification settings - Fork 13
Implement Inference Models and Namespaces APIs #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Inference Models and Namespaces APIs #107
Conversation
…r dense embeddings, add a few things for models API wiring
…thods to InferenceService
…d in the index_connection file
… a set of namespaces rather than one, add integration tests for namespaces and models APIs
@@ -588,8 +588,10 @@ Pinecone indexes support working with vector data using operations such as upser | |||
|
|||
### Targeting an index | |||
|
|||
To perform data operations on an index, you target it using the `Index` method on a `Client` object. You will | |||
need your index's `Host` value, which you can retrieve via `DescribeIndex` or `ListIndexes`. | |||
To perform data operations on an index, you target it using the `Index` method on a `Client` object which returns a pointer to an `IndexConnection`. Calling `Index` will create and dial the index via a new gRPC connection. You can target a specific `Namespace` when calling `Index`, but if you want to reuse the connection with different namespaces, you can call `IndexConnection.WithNamespace`. If no `Namespace` is provided when establishing a new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a bunch of cleaning up of README / doc comments which I noticed were either a bit dated, unclear, or needed changing due to some of the refactoring. There's a lot more to do, I need to do a real look over all of our examples and docs at some point.
@@ -1537,16 +1541,9 @@ type EmbedRequest struct { | |||
// [EmbedParameters] contains model-specific parameters that can be used for generating embeddings. | |||
// | |||
// Fields: | |||
// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleaning up some weirdly formatted comments.
err := json.NewDecoder(resBody).Decode(&embeddingsList) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to decode embeddings response: %w", err) | ||
func decodeEmbedResponse(resBody io.ReadCloser) (*EmbedResponse, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a portion of the mentioned refactor to support both sparse and dense embedding responses. Check the models.go
file for the associated types.
require.Equal(ts.T(), true, allDenseModels, "Expected all listed models to be of vector type 'dense'") | ||
} | ||
|
||
func (ts *IntegrationTests) TestGenerateEmbeddingsDense() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Integration tests for generating sparse and dense embeddings.
// - additionalMetadata: Additional metadata to be sent with each RPC request. | ||
// - dataClient: The gRPC client for the index. | ||
// - grpcConn: The gRPC connection. | ||
type IndexConnection struct { | ||
Namespace string | ||
namespace string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making this a private field on IndexConnection
.
// | ||
// Returns the number of vectors upserted or an error if the request fails. | ||
// [IndexConnection.Namespace] allows returning the namespace the instance of [IndexConnection] is targeting. | ||
func (idx *IndexConnection) Namespace() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exposing a getter for the current namespace.
// if err != nil { | ||
// log.Fatalf("Failed to upsert vectors in %s. Error: %v", idxConnNs2.Namespace, err) | ||
// } | ||
func (idx *IndexConnection) WithNamespace(namespace string) *IndexConnection { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes a shallow copy of the IndexConnection
, which re-shares the underlying gRPC connection. This should be threadsafe from what I understand, while allowing people to reuse the connection.
// | ||
// idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: idx.Host}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of doc comment cleanup, apologies.
@@ -1581,6 +1777,42 @@ func (idx *IndexConnection) delete(ctx context.Context, req *db_data_grpc.Delete | |||
return err | |||
} | |||
|
|||
func decodeSearchRecordsResponse(body io.ReadCloser) (*SearchRecordsResponse, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of this is reshuffling things around plus some minor cleanup.
@@ -232,7 +281,7 @@ const ( | |||
Pending ImportStatus = "Pending" | |||
) | |||
|
|||
// ImportErrorMode specifies how errors are handled during an [Import]. | |||
// [ImportErrorMode] specifies how errors are handled during an [Import]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More doc comment nitpicky stuff - these just make these hyperlinks in the resulting Go docs which we do in most other places.
log.Fatalf("Failed to upsert vectors in SetupSuite: %v", err) | ||
// Upsert vectors into each namespace | ||
for _, ns := range namespaces { | ||
idxConnNamespaced := ts.idxConn.WithNamespace(ns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using WithNamespace
here to seed the integration test index with multiple namespaces rather than one. This is leveraged in integration tests around the namespace operations.
@@ -77,8 +85,6 @@ func (ts *IntegrationTests) SetupSuite() { | |||
} | |||
|
|||
fmt.Printf("\n %s set up suite completed successfully\n", ts.indexType) | |||
|
|||
// Poll for data freshness |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was removed from the test setup at some point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for being diligent on docs
## Problem Inference Models and Namespaces are new API resources available in `2025-04`. They need to be implemented in the Go client. Additionally, there are a few client bugs which need to be fixed: - The `Embed` method and it's return type `EmbedResponse` need to be refactored to support both sparse and dense embedding responses, rather than just dense. Currently, embedding with a model that returns sparse values will cause errors. - The `IndexConnection` struct is not safe to reuse for performing operations across namespaces while reusing the existing gRPC connection for the index. This is because `IndexConnection.Namespace` is publicly exposed, and could be updated at any point. ## Solution Implement new namespaces and models API operations: - Namespace operations have been implemented on `IndexConnection`. They're exposed as methods which you can call via `IndexConnection.ListNamespaces`, `IndexConnection.DescribeNamespace`, or `IndexConnection.DeleteNamespace`. - Hosted model operations can be performed using the `Client.Inference` namespace (`InferenceService` struct) by calling `client.Inference.DescribeModel` or `client.Inference.ListModels`. The `InferenceService.Embed` method now returns a different `Embedding` inside of `EmbedResponse`. `Embedding` has been refactored into a tagged union type which is basically just a struct that wraps either a `SparseEmbedding` or `DenseEmbedding` pointers. This seemed to be the best way to manage this type of thing in Go given the lack of explicit union types. I'm open to suggestions if anyone has something that may be a bit more ergonomic. `IndexConnection` has been refactored to no longer expose `IndexConnection.Namespace` directly. Instead, `Namespace` is now a method which allows checking the currently targeted namespace. Users can now call `IndexConnection.WithNamespace` which will return a copy of the `IndexConnection` targeting the new namespace, but sharing the underlying gRPC connection. Again, I think this is a reasonable way of approaching this and allowing safely targeting multiple namespaces within an index, but I'm open to feedback. ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [X] Breaking change (fix or feature that would cause existing functionality to not work as expected) - Breaking change for `EmbedResponse` on `InferenceService.Embed` - [ ] This change requires a documentation update - [ ] Infrastructure change (CI configs, etc) - [ ] Non-code change (docs, etc) - [ ] None of the above: (explain here) ## Test Plan CI - unit tests & integration tests If you'd like to test the new APIs out yourself you can check the integration tests or README for more detailed examples: Models: ```go ctx := context.Background() pc, err := pinecone.NewClient(pinecone.NewClientParams{ ApiKey: "YOUR_API_KEY", }) if err != nil { log.Fatalf("Failed to create Client: %v", err) } embed := "embed" rerank := "rerank" embedModels, err := pc.Inference.ListModels(ctx, &pinecone.ListModelsParams{ Type: &embed, }) if err != nil { log.Fatalf("Failed to list embedding models: %v", err) } rerankModels, err := pc.Inference.ListModels(ctx, &pinecone.ListModelsParams{ Type: &rerank, }) if err != nil { log.Fatalf("Failed to list reranking models: %v", err) } multilingualModel, := pc.Inference.DescribeModel(ctx, "multilingual-e5-large") if err != nil { log.Fatalf("Failed to describe models: %v", err) } ``` Namespaces: ```go ctx := context.Background() pc, err := pinecone.NewClient(pinecone.NewClientParams{ ApiKey: "YOUR_API_KEY", }) if err != nil { log.Fatalf("Failed to create Client: %v", err) } idx, err := pc.DescribeIndex(ctx, "example-index") if err != nil { log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err) } idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: idx.Host}) if err != nil { log.Fatalf("Failed to create IndexConnection for Host: %v: %v", idx.Host, err) } // list namespaces limit := uint32(10) namespaces, err := idxConnection.ListNamespaces(ctx, &pinecone.ListNamespacesParams{ Limit: &limit, }) if err != nil { log.Fatalf("Failed to list namespaces for Host: %v: %v", idx.Host, err) } // describe a namespace namespace1, err := idxConnection.DescribeNamespace(ctx, "my-namespace-1") if err != nil { log.Fatalf("Failed to describe namespace: %v: %v", "my-namespace-1", err) } // delete a namespace err := idxConnection.DeleteNamespace("my-namespace-1") if err != nil { log.Fatalf("Failed to delete namespace: %v: %v", "my-namespace-1", err) } ``` --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1210238631289243 - https://app.asana.com/0/0/1209828518477630
## Problem Inference Models and Namespaces are new API resources available in `2025-04`. They need to be implemented in the Go client. Additionally, there are a few client bugs which need to be fixed: - The `Embed` method and it's return type `EmbedResponse` need to be refactored to support both sparse and dense embedding responses, rather than just dense. Currently, embedding with a model that returns sparse values will cause errors. - The `IndexConnection` struct is not safe to reuse for performing operations across namespaces while reusing the existing gRPC connection for the index. This is because `IndexConnection.Namespace` is publicly exposed, and could be updated at any point. ## Solution Implement new namespaces and models API operations: - Namespace operations have been implemented on `IndexConnection`. They're exposed as methods which you can call via `IndexConnection.ListNamespaces`, `IndexConnection.DescribeNamespace`, or `IndexConnection.DeleteNamespace`. - Hosted model operations can be performed using the `Client.Inference` namespace (`InferenceService` struct) by calling `client.Inference.DescribeModel` or `client.Inference.ListModels`. The `InferenceService.Embed` method now returns a different `Embedding` inside of `EmbedResponse`. `Embedding` has been refactored into a tagged union type which is basically just a struct that wraps either a `SparseEmbedding` or `DenseEmbedding` pointers. This seemed to be the best way to manage this type of thing in Go given the lack of explicit union types. I'm open to suggestions if anyone has something that may be a bit more ergonomic. `IndexConnection` has been refactored to no longer expose `IndexConnection.Namespace` directly. Instead, `Namespace` is now a method which allows checking the currently targeted namespace. Users can now call `IndexConnection.WithNamespace` which will return a copy of the `IndexConnection` targeting the new namespace, but sharing the underlying gRPC connection. Again, I think this is a reasonable way of approaching this and allowing safely targeting multiple namespaces within an index, but I'm open to feedback. ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [X] Breaking change (fix or feature that would cause existing functionality to not work as expected) - Breaking change for `EmbedResponse` on `InferenceService.Embed` - [ ] This change requires a documentation update - [ ] Infrastructure change (CI configs, etc) - [ ] Non-code change (docs, etc) - [ ] None of the above: (explain here) ## Test Plan CI - unit tests & integration tests If you'd like to test the new APIs out yourself you can check the integration tests or README for more detailed examples: Models: ```go ctx := context.Background() pc, err := pinecone.NewClient(pinecone.NewClientParams{ ApiKey: "YOUR_API_KEY", }) if err != nil { log.Fatalf("Failed to create Client: %v", err) } embed := "embed" rerank := "rerank" embedModels, err := pc.Inference.ListModels(ctx, &pinecone.ListModelsParams{ Type: &embed, }) if err != nil { log.Fatalf("Failed to list embedding models: %v", err) } rerankModels, err := pc.Inference.ListModels(ctx, &pinecone.ListModelsParams{ Type: &rerank, }) if err != nil { log.Fatalf("Failed to list reranking models: %v", err) } multilingualModel, := pc.Inference.DescribeModel(ctx, "multilingual-e5-large") if err != nil { log.Fatalf("Failed to describe models: %v", err) } ``` Namespaces: ```go ctx := context.Background() pc, err := pinecone.NewClient(pinecone.NewClientParams{ ApiKey: "YOUR_API_KEY", }) if err != nil { log.Fatalf("Failed to create Client: %v", err) } idx, err := pc.DescribeIndex(ctx, "example-index") if err != nil { log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err) } idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: idx.Host}) if err != nil { log.Fatalf("Failed to create IndexConnection for Host: %v: %v", idx.Host, err) } // list namespaces limit := uint32(10) namespaces, err := idxConnection.ListNamespaces(ctx, &pinecone.ListNamespacesParams{ Limit: &limit, }) if err != nil { log.Fatalf("Failed to list namespaces for Host: %v: %v", idx.Host, err) } // describe a namespace namespace1, err := idxConnection.DescribeNamespace(ctx, "my-namespace-1") if err != nil { log.Fatalf("Failed to describe namespace: %v: %v", "my-namespace-1", err) } // delete a namespace err := idxConnection.DeleteNamespace("my-namespace-1") if err != nil { log.Fatalf("Failed to delete namespace: %v: %v", "my-namespace-1", err) } ``` --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1210238631289243 - https://app.asana.com/0/0/1209828518477630
Problem
Inference Models and Namespaces are new API resources available in
2025-04
. They need to be implemented in the Go client.Additionally, there are a few client bugs which need to be fixed:
Embed
method and it's return typeEmbedResponse
need to be refactored to support both sparse and dense embedding responses, rather than just dense. Currently, embedding with a model that returns sparse values will cause errors.IndexConnection
struct is not safe to reuse for performing operations across namespaces while reusing the existing gRPC connection for the index. This is becauseIndexConnection.Namespace
is publicly exposed, and could be updated at any point.Solution
Implement new namespaces and models API operations:
IndexConnection
. They're exposed as methods which you can call viaIndexConnection.ListNamespaces
,IndexConnection.DescribeNamespace
, orIndexConnection.DeleteNamespace
.Client.Inference
namespace (InferenceService
struct) by callingclient.Inference.DescribeModel
orclient.Inference.ListModels
.The
InferenceService.Embed
method now returns a differentEmbedding
inside ofEmbedResponse
.Embedding
has been refactored into a tagged union type which is basically just a struct that wraps either aSparseEmbedding
orDenseEmbedding
pointers. This seemed to be the best way to manage this type of thing in Go given the lack of explicit union types. I'm open to suggestions if anyone has something that may be a bit more ergonomic.IndexConnection
has been refactored to no longer exposeIndexConnection.Namespace
directly. Instead,Namespace
is now a method which allows checking the currently targeted namespace. Users can now callIndexConnection.WithNamespace
which will return a copy of theIndexConnection
targeting the new namespace, but sharing the underlying gRPC connection. Again, I think this is a reasonable way of approaching this and allowing safely targeting multiple namespaces within an index, but I'm open to feedback.Type of Change
EmbedResponse
onInferenceService.Embed
Test Plan
CI - unit tests & integration tests
If you'd like to test the new APIs out yourself you can check the integration tests or README for more detailed examples:
Models:
Namespaces: