Files
Nicolò Boschi ef3ccdba3a fix(api): type the list and graph rows instead of returning bare dicts (#4218) (#4233)
* fix(api): type the list and graph rows instead of returning bare dicts (#4218)

`list_memories`, `list_documents`, `get_graph` and `get_entity_graph` declared
their rows as `dict[str, Any]`, so every generated SDK handed callers untyped
dicts while the single-fetch siblings returned real models — `listing.items[0].id`
failed with an `AttributeError` and a server-side rename became a runtime
`KeyError` rather than a build error.

Each row now has a model (`DocumentListItem`, `MemoryUnitListItem`, the Cytoscape
node/edge envelopes and `MemoryGraphTableRow`), sharing an `OpenRowModel` base
that keeps the wire byte-identical:

- `extra="allow"`, so a key the server emits and the model does not declare still
  reaches the client — a memories store that owns its own document or entity
  registry builds these rows itself.
- the routes keep emitting nulls. `ExcludeNoneRoute` was already enabling
  `response_model_exclude_none` for them, but `exclude_none` never reached inside
  a `dict` value, so the rows' nulls were always on the wire; typing them would
  have started dropping those keys.

`additionalProperties` is stripped from the published schema: openapi-generator
7.10.0's Python generator crashes on a schema pairing it with a nullable `anyOf`
property, which every row here has.

The CLI moves to attribute access, which exposes a latent bug in `bank graph`:
its node lookups read `node["type"]`/`node["id"]` through the Cytoscape `data`
envelope, so the sample always printed "unknown [unknown]" with no text.

* docs(examples): read list rows by attribute now that they are typed
2026-09-08 18:48:52 +02:00

93 lines
2.5 KiB
Go

package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
hindsight "github.com/vectorize-io/hindsight/hindsight-clients/go"
)
func main() {
apiURL := os.Getenv("HINDSIGHT_API_URL")
if apiURL == "" {
apiURL = "http://localhost:8888"
}
cfg := hindsight.NewConfiguration()
cfg.Servers = hindsight.ServerConfigurations{{URL: apiURL}}
client := hindsight.NewAPIClient(cfg)
ctx := context.Background()
// [docs:document-retain]
// Retain with document ID
docID := "meeting-2024-03-15"
client.MemoryAPI.RetainMemories(ctx, "my-bank").
RetainRequest(hindsight.RetainRequest{
Items: []hindsight.MemoryItem{
{
Content: hindsight.TextContent("Alice presented the Q4 roadmap..."),
DocumentId: *hindsight.NewNullableString(&docID),
},
},
}).Execute()
// [/docs:document-retain]
// [docs:document-update]
// Original
planDoc := "project-plan"
client.MemoryAPI.RetainMemories(ctx, "my-bank").
RetainRequest(hindsight.RetainRequest{
Items: []hindsight.MemoryItem{
{
Content: hindsight.TextContent("Project deadline: March 31"),
DocumentId: *hindsight.NewNullableString(&planDoc),
},
},
}).Execute()
// Update (deletes old facts, creates new ones)
client.MemoryAPI.RetainMemories(ctx, "my-bank").
RetainRequest(hindsight.RetainRequest{
Items: []hindsight.MemoryItem{
{
Content: hindsight.TextContent("Project deadline: April 15 (extended)"),
DocumentId: *hindsight.NewNullableString(&planDoc),
},
},
}).Execute()
// [/docs:document-update]
// [docs:document-get]
doc, _, err := client.DocumentsAPI.GetDocument(ctx, "my-bank", "meeting-2024-03-15").Execute()
if err != nil {
log.Fatalf("Failed to get document: %v", err)
}
fmt.Printf("Document ID: %s\n", doc.GetId())
fmt.Printf("Memory units: %d\n", doc.GetMemoryUnitCount())
// [/docs:document-get]
// [docs:document-delete]
client.DocumentsAPI.DeleteDocument(ctx, "my-bank", "meeting-2024-03-15").Execute()
// [/docs:document-delete]
// [docs:document-list]
// List all documents
docs, _, err := client.DocumentsAPI.ListDocuments(ctx, "my-bank").Execute()
if err != nil {
log.Fatalf("Failed to list documents: %v", err)
}
for _, d := range docs.Items {
fmt.Printf("%s: %d memories\n", d.Id, d.GetMemoryUnitCount())
}
// [/docs:document-list]
// Cleanup (not shown in docs)
req, _ := http.NewRequest("DELETE", fmt.Sprintf("%s/v1/default/banks/my-bank", apiURL), nil)
http.DefaultClient.Do(req)
fmt.Println("documents.go: All examples passed")
}