mirror of
https://github.com/volcengine/OpenViking.git
synced 2026-09-30 17:28:07 +08:00
* feat(sdk): sync go/ts/python SDKs with server find/search, recall, and admin changes Server-side changes recently landed that the language SDKs had drifted from: - find/search results now return `tags` and no longer return `category`/`match_reason`/`relations`/`overview` (#3730). Go's strict struct was the only one broken; update MatchedContext accordingly. - new admin endpoints for agent-evolution and per-account settings (#3695). - public `search/recall` endpoint was missing from all SDKs. Changes: - python: add `level`/`since`/`until`/`time_field` to find/search; add an `extra` escape hatch to find/search/add_resource/write/batch_write so new server fields can be passed without an SDK bump (only forwarded when set, preserving `level=0`); add `recall` and the four admin methods. - go: fix MatchedContext (add Tags, drop removed fields), add Recall and the four admin methods. - typescript: type MatchedContext/FindResult, add RecallOptions, add `recall` and the four admin methods. Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> feat(sdk): unify options APIs and sync latest server interfaces - migrate complex Python SDK calls to typed options dictionaries - add dedicated context search and consistent extra-field handling - align Go and TypeScript options with omission-aware serialization - support session config, event tags, Agent Evolution date filters, OpenViking Assets, batch write, downloads, and create_parent - refresh SDK tests and examples across all three languages Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): address options API review findings - fix Go session extra merging and Python message precedence - adapt LangChain calls to the Python options API - migrate repository examples, tests, and documentation Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): complete options migration and message parity - migrate remaining Python SDK benchmarks to options dictionaries - normalize empty parts consistently for single and batch messages - add regression guards for repository SDK call sites Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): align reindex options after main rebase - preserve reindex tags in Python typed options - add reindex extra support for Go and TypeScript - reject official fields passed through extra across SDKs Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> feat(sdk): support legacy keyword options Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> docs(sdk): use explicit Python SDK arguments Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): support set tags extra options Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): expose Go add resource options Expose AddType and ProcessingMode through Go AddResourceOptions and serialize them to the resources API. Add a regression test covering the resulting request payload. Co-authored-by: TRAE CLI <noreply@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com> feat(sdk): flatten core Python client options Co-authored-by: TRAE CLI <traecli@bytedance.com> docs(sdk): align Python examples with flattened options Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): preserve core API compatibility Co-authored-by: TRAE CLI <traecli@bytedance.com> refactor(python-sdk): move resource hints to options Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): align resource option callers Co-authored-by: TRAE CLI <traecli@bytedance.com> test(sdk): cover recursive reindex forwarding Co-authored-by: TRAE CLI <traecli@bytedance.com> fix(sdk): preserve Go options compatibility Co-authored-by: TRAE CLI <traecli@bytedance.com> feat(python-sdk): expose message peer id Co-authored-by: TRAE CLI <traecli@bytedance.com> test(python-sdk): consolidate options coverage Co-authored-by: TRAE CLI <traecli@bytedance.com> feat(python-sdk): add parts and flatten image search Co-authored-by: TRAE CLI <traecli@bytedance.com> * docs(sdk): align Python call examples Co-authored-by: TRAE CLI <traecli@bytedance.com> --------- Co-authored-by: TRAE CLI <traecli@bytedance.com> Co-authored-by: Qin Haojie <qinhaojie.exe@bytedance.com>
303 lines
9.0 KiB
Go
303 lines
9.0 KiB
Go
package openviking
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
)
|
|
|
|
// List lists directory contents.
|
|
func (c *Client) List(ctx context.Context, uri string, opts *ListOptions) ([]any, error) {
|
|
if opts == nil {
|
|
opts = &ListOptions{Output: "original", AbsLimit: 256, NodeLimit: 1000}
|
|
}
|
|
output := opts.Output
|
|
if output == "" {
|
|
output = "original"
|
|
}
|
|
absLimit := opts.AbsLimit
|
|
if absLimit == 0 {
|
|
absLimit = 256
|
|
}
|
|
nodeLimit := opts.NodeLimit
|
|
if nodeLimit == 0 {
|
|
nodeLimit = 1000
|
|
}
|
|
query := url.Values{}
|
|
query.Set("uri", NormalizeURI(uri))
|
|
queryBool(query, "simple", opts.Simple)
|
|
queryBool(query, "recursive", opts.Recursive)
|
|
query.Set("output", output)
|
|
queryInt(query, "abs_limit", absLimit)
|
|
queryBool(query, "show_all_hidden", opts.ShowAllHidden)
|
|
queryInt(query, "node_limit", nodeLimit)
|
|
if opts.SortBy != "" {
|
|
query.Set("sort_by", opts.SortBy)
|
|
}
|
|
if opts.SortOrder != "" {
|
|
query.Set("sort_order", opts.SortOrder)
|
|
}
|
|
var result []any
|
|
err := c.doJSON(ctx, http.MethodGet, "/api/v1/fs/ls", query, nil, &result)
|
|
return result, err
|
|
}
|
|
|
|
// Tree returns a directory tree.
|
|
func (c *Client) Tree(ctx context.Context, uri string, opts *TreeOptions) ([]map[string]any, error) {
|
|
if opts == nil {
|
|
opts = &TreeOptions{Output: "original", AbsLimit: 128, NodeLimit: 1000}
|
|
}
|
|
output := opts.Output
|
|
if output == "" {
|
|
output = "original"
|
|
}
|
|
absLimit := opts.AbsLimit
|
|
if absLimit == 0 {
|
|
absLimit = 128
|
|
}
|
|
nodeLimit := opts.NodeLimit
|
|
if nodeLimit == 0 {
|
|
nodeLimit = 1000
|
|
}
|
|
levelLimit := 3
|
|
if opts.LevelLimit != nil {
|
|
levelLimit = *opts.LevelLimit
|
|
}
|
|
query := url.Values{}
|
|
query.Set("uri", NormalizeURI(uri))
|
|
query.Set("output", output)
|
|
queryInt(query, "abs_limit", absLimit)
|
|
queryBool(query, "show_all_hidden", opts.ShowAllHidden)
|
|
queryInt(query, "node_limit", nodeLimit)
|
|
queryInt(query, "level_limit", levelLimit)
|
|
var result []map[string]any
|
|
err := c.doJSON(ctx, http.MethodGet, "/api/v1/fs/tree", query, nil, &result)
|
|
return result, err
|
|
}
|
|
|
|
// Stat returns metadata for a URI.
|
|
func (c *Client) Stat(ctx context.Context, uri string) (map[string]any, error) {
|
|
query := url.Values{"uri": []string{NormalizeURI(uri)}}
|
|
var result map[string]any
|
|
err := c.doJSON(ctx, http.MethodGet, "/api/v1/fs/stat", query, nil, &result)
|
|
return result, err
|
|
}
|
|
|
|
// Attrs returns logical extended attributes for a URI.
|
|
func (c *Client) Attrs(ctx context.Context, uri string) (map[string]any, error) {
|
|
query := url.Values{"uri": []string{NormalizeURI(uri)}}
|
|
var result map[string]any
|
|
err := c.doJSON(ctx, http.MethodGet, "/api/v1/fs/attrs", query, nil, &result)
|
|
return result, err
|
|
}
|
|
|
|
// Mkdir creates a directory.
|
|
func (c *Client) Mkdir(ctx context.Context, uri string, description string) error {
|
|
payload := map[string]any{"uri": NormalizeURI(uri)}
|
|
setString(payload, "description", description)
|
|
return c.doJSON(ctx, http.MethodPost, "/api/v1/fs/mkdir", nil, payload, nil)
|
|
}
|
|
|
|
// Remove deletes a URI.
|
|
func (c *Client) Remove(ctx context.Context, uri string, opts *RemoveOptions) error {
|
|
if opts == nil {
|
|
opts = &RemoveOptions{}
|
|
}
|
|
query := url.Values{}
|
|
query.Set("uri", NormalizeURI(uri))
|
|
queryBool(query, "recursive", opts.Recursive)
|
|
queryBool(query, "wait", opts.Wait)
|
|
if opts.Timeout != nil {
|
|
queryFloat(query, "timeout", *opts.Timeout)
|
|
}
|
|
return c.doJSON(ctx, http.MethodDelete, "/api/v1/fs", query, nil, nil)
|
|
}
|
|
|
|
// Move moves a URI to another URI.
|
|
func (c *Client) Move(ctx context.Context, fromURI, toURI string) error {
|
|
return c.doJSON(ctx, http.MethodPost, "/api/v1/fs/mv", nil, map[string]any{
|
|
"from_uri": NormalizeURI(fromURI),
|
|
"to_uri": NormalizeURI(toURI),
|
|
}, nil)
|
|
}
|
|
|
|
// Read reads file content.
|
|
func (c *Client) Read(ctx context.Context, uri string, offset int, limit int) (string, error) {
|
|
query := url.Values{}
|
|
query.Set("uri", NormalizeURI(uri))
|
|
queryInt(query, "offset", offset)
|
|
queryInt(query, "limit", limit)
|
|
var result string
|
|
err := c.doJSON(ctx, http.MethodGet, "/api/v1/content/read", query, nil, &result)
|
|
return result, err
|
|
}
|
|
|
|
// DownloadBytes downloads raw stored bytes.
|
|
func (c *Client) DownloadBytes(ctx context.Context, uri string) ([]byte, error) {
|
|
query := url.Values{"uri": []string{NormalizeURI(uri)}}
|
|
req, err := c.newRequest(ctx, http.MethodGet, "/api/v1/content/download", query, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp, err := c.httpClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
data, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
env, decodeErr := decodeEnvelope(resp.StatusCode, data)
|
|
if decodeErr != nil {
|
|
return nil, decodeErr
|
|
}
|
|
if env.Error != nil {
|
|
return nil, apiError(resp.StatusCode, env.Error)
|
|
}
|
|
return nil, &Error{
|
|
Code: "UNKNOWN",
|
|
Message: envelopeDetail(env, resp.StatusCode, data),
|
|
StatusCode: resp.StatusCode,
|
|
}
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
// Abstract reads L0 abstract content.
|
|
func (c *Client) Abstract(ctx context.Context, uri string) (string, error) {
|
|
query := url.Values{"uri": []string{NormalizeURI(uri)}}
|
|
var result string
|
|
err := c.doJSON(ctx, http.MethodGet, "/api/v1/content/abstract", query, nil, &result)
|
|
return result, err
|
|
}
|
|
|
|
// Overview reads L1 overview content.
|
|
func (c *Client) Overview(ctx context.Context, uri string) (string, error) {
|
|
query := url.Values{"uri": []string{NormalizeURI(uri)}}
|
|
var result string
|
|
err := c.doJSON(ctx, http.MethodGet, "/api/v1/content/overview", query, nil, &result)
|
|
return result, err
|
|
}
|
|
|
|
// Write writes text content and refreshes related semantics/vectors.
|
|
func (c *Client) Write(ctx context.Context, uri string, content string, opts *WriteOptions) (map[string]any, error) {
|
|
if opts == nil {
|
|
opts = &WriteOptions{}
|
|
}
|
|
mode := opts.Mode
|
|
if mode == "" {
|
|
mode = "replace"
|
|
}
|
|
payload := map[string]any{
|
|
"uri": NormalizeURI(uri),
|
|
"content": content,
|
|
"mode": mode,
|
|
"wait": opts.Wait,
|
|
}
|
|
setFloatPtr(payload, "timeout", opts.Timeout)
|
|
setAny(payload, "telemetry", opts.Telemetry)
|
|
setString(payload, "processing_mode", opts.ProcessingMode)
|
|
if err := mergeExtra(payload, opts.Extra); err != nil {
|
|
return nil, err
|
|
}
|
|
var result map[string]any
|
|
err := c.doJSON(ctx, http.MethodPost, "/api/v1/content/write", nil, payload, &result)
|
|
return result, err
|
|
}
|
|
|
|
// BatchWrite applies preconditioned file writes in one request.
|
|
func (c *Client) BatchWrite(
|
|
ctx context.Context,
|
|
rootURI string,
|
|
operations []BatchWriteOperation,
|
|
opts *BatchWriteOptions,
|
|
) (map[string]any, error) {
|
|
normalized := make([]BatchWriteOperation, len(operations))
|
|
copy(normalized, operations)
|
|
for i := range normalized {
|
|
normalized[i].URI = NormalizeURI(normalized[i].URI)
|
|
}
|
|
payload := map[string]any{
|
|
"root_uri": NormalizeURI(rootURI),
|
|
"operations": normalized,
|
|
}
|
|
if opts != nil {
|
|
setAny(payload, "wait", opts.Wait)
|
|
setFloatPtr(payload, "timeout", opts.Timeout)
|
|
setAny(payload, "telemetry", opts.Telemetry)
|
|
if err := mergeExtra(payload, opts.Extra); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
var result map[string]any
|
|
err := c.doJSON(ctx, http.MethodPost, "/api/v1/content/batch-write", nil, payload, &result)
|
|
return result, err
|
|
}
|
|
|
|
// SetTags sets explicit k=v retrieval tags metadata for a file or directory.
|
|
// Valid modes are "replace" (default) and "append"; Recursive applies the tags
|
|
// to every file under a directory URI.
|
|
func (c *Client) SetTags(ctx context.Context, uri string, tags []string, opts *SetTagsOptions) (map[string]any, error) {
|
|
if opts == nil {
|
|
opts = &SetTagsOptions{Mode: "replace"}
|
|
}
|
|
mode := opts.Mode
|
|
if mode == "" {
|
|
mode = "replace"
|
|
}
|
|
// The server contract is tags:list[str]; a nil slice would marshal to JSON
|
|
// null and fail validation, so normalize to an empty list. With mode
|
|
// "replace" an empty list clears all tags.
|
|
if tags == nil {
|
|
tags = []string{}
|
|
}
|
|
payload := map[string]any{
|
|
"uri": NormalizeURI(uri),
|
|
"tags": tags,
|
|
"mode": mode,
|
|
"recursive": opts.Recursive,
|
|
}
|
|
setAny(payload, "telemetry", opts.Telemetry)
|
|
if err := mergeExtraProtected(payload, opts.Extra, "uri", "tags", "mode", "recursive", "telemetry"); err != nil {
|
|
return nil, err
|
|
}
|
|
var result map[string]any
|
|
err := c.doJSON(ctx, http.MethodPost, "/api/v1/fs/attrs/set_tags", nil, payload, &result)
|
|
return result, err
|
|
}
|
|
|
|
// Reindex triggers reindexing for a URI.
|
|
func (c *Client) Reindex(ctx context.Context, uri string, opts *ReindexOptions) (map[string]any, error) {
|
|
if opts == nil {
|
|
opts = &ReindexOptions{Mode: "vectors_only", Wait: true}
|
|
}
|
|
mode := opts.Mode
|
|
if mode == "" {
|
|
mode = "vectors_only"
|
|
}
|
|
payload := map[string]any{
|
|
"uri": NormalizeURI(uri),
|
|
"mode": mode,
|
|
"wait": opts.Wait,
|
|
"dry_run": opts.DryRun,
|
|
"recursive": boolValue(opts.Recursive, true),
|
|
}
|
|
if opts.Tags != nil {
|
|
payload["tags"] = opts.Tags
|
|
tagMode := opts.TagMode
|
|
if tagMode == "" {
|
|
tagMode = "replace"
|
|
}
|
|
payload["tag_mode"] = tagMode
|
|
}
|
|
if err := mergeExtraProtected(payload, opts.Extra, "tags", "tag_mode"); err != nil {
|
|
return nil, err
|
|
}
|
|
var result map[string]any
|
|
err := c.doJSON(ctx, http.MethodPost, "/api/v1/content/reindex", nil, payload, &result)
|
|
return result, err
|
|
}
|