Files
OpenViking/examples/cloud/bob.py
T
9eac8a6d3d feat(sdk): sync go/ts/python SDKs with server find/search, recall, an… (#3737)
* 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>
2026-08-24 14:09:11 +08:00

223 lines
8.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Bob — 新入职成员的使用流程
操作:浏览团队资源 → 回顾团队记忆 → 添加自己的资源 → 对话 → 沉淀记忆 → 带上下文搜索
获取 API Key:
API Key 由租户管理员分配,流程如下:
1. 管理员(如 Alice)用自己的 Key 注册 Bob:
curl -X POST http://localhost:1933/api/v1/admin/accounts/demo-team/users \
-H "X-API-Key: <alice_key>" -H "Content-Type: application/json" \
-d '{"user_id": "bob", "role": "user"}'
返回中的 user_key 就是 Bob 的 API Key
2. 或者运行 setup_users.py 自动完成,Key 写入 user_keys.json
运行(建议在 alice.py 之后执行,这样可以看到 Alice 沉淀的团队记忆):
uv run examples/cloud/bob.py
uv run examples/cloud/bob.py --url http://localhost:1933 --api-key <bob_key>
"""
import argparse
import json
import sys
import time
import openviking as ov
from openviking_cli.utils.async_utils import run_async
def load_key_from_file(user="bob"):
try:
with open("examples/cloud/user_keys.json") as f:
keys = json.load(f)
return keys["url"], keys[f"{user}_key"]
except (FileNotFoundError, KeyError):
return None, None
def main():
parser = argparse.ArgumentParser(description="Bob 的使用流程")
parser.add_argument("--url", default=None, help="Server URL")
parser.add_argument("--api-key", default=None, help="Bob 的 API Key")
args = parser.parse_args()
url, api_key = args.url, args.api_key
if not api_key:
url_from_file, key_from_file = load_key_from_file("bob")
url = url or url_from_file or "http://localhost:1933"
api_key = key_from_file
if not url:
url = "http://localhost:1933"
if not api_key:
print("请通过 --api-key 指定 API Key,或先运行 setup_users.py")
sys.exit(1)
print(f"Server: {url}")
print("User: bob")
print("Key: [hidden]")
client = ov.SyncHTTPClient(url=url, api_key=api_key)
client.initialize()
try:
# ── 1. 浏览团队已有资源 ──
print("\n== 1. 浏览团队资源 ==")
entries = client.ls("viking://")
if not entries:
print(" (空,Alice 还没添加资源)")
for entry in entries:
if isinstance(entry, dict):
kind = "dir " if entry.get("isDir") else "file"
print(f" [{kind}] {entry.get('name', '?')}")
# ── 2. 回顾团队记忆(Alice 沉淀的技术决策) ──
print("\n== 2. 回顾团队记忆: '项目技术选型' ==")
results = client.find(query="项目用了什么技术栈和架构选型", limit=5)
memories = results.get("memories", [])
if memories:
print(" 团队记忆:")
for index, memory in enumerate(memories, 1):
description = (
memory.get("abstract")
or memory.get("overview")
or memory.get("uri", "")
)
print(f" {index}. [{memory.get('score', 0.0):.3f}] {description[:150]}")
else:
print(" 未找到团队记忆(Alice 可能还没执行 commit)")
resources = results.get("resources", [])
if resources:
print(" 相关资源:")
for index, resource in enumerate(resources, 1):
print(
f" {index}. [{resource.get('score', 0.0):.3f}] "
f"{resource['uri']}"
)
# ── 3. 搜索具体决策 ──
print("\n== 3. 搜索: '存储方案 TOS 配置' ==")
results = client.find(query="文件存储方案 TOS bucket 配置", limit=3)
memories = results.get("memories", [])
if memories:
for index, memory in enumerate(memories, 1):
description = (
memory.get("abstract")
or memory.get("overview")
or memory.get("uri", "")
)
print(f" {index}. [{memory.get('score', 0.0):.3f}] {description[:150]}")
else:
print(" 未找到相关记忆")
# ── 4. 添加自己的资源 ──
print("\n== 4. 添加资源: CONTRIBUTING.md ==")
result = client.add_resource(
path="https://raw.githubusercontent.com/volcengine/OpenViking/refs/heads/main/CONTRIBUTING.md",
options={"reason": "贡献指南学习笔记"},
)
bob_uri = result.get("root_uri", "")
print(f" URI: {bob_uri}")
print(" 等待处理...")
client.wait_processed(timeout=120)
print(" 完成")
# ── 5. 创建会话,模拟入职学习 ──
print("\n== 5. 对话: 入职学习 ==")
session_info = client.create_session()
session = client.session(session_id=session_info["session_id"])
print(f" Session: {session.session_id}")
messages = [
("user", "我刚入职,需要了解 OpenViking 的贡献流程"),
(
"assistant",
"欢迎!贡献流程主要是:1) Fork 仓库 2) 创建 feature branch "
"3) 提交 PR 并通过 CI 4) Code Review 后合并。"
"代码规范见 CONTRIBUTING.md。",
),
("user", "本地开发环境怎么搭建?"),
(
"assistant",
"本地开发步骤:1) 安装 Python 3.10+ 和 uv "
"2) git clone 后执行 uv sync 安装依赖 "
"3) 复制 examples/ov.conf.example 为 ~/.openviking/ov.conf 填入 API Key "
"4) 运行 openviking-server 启动开发服务。构建 abi3 C++ 扩展需要 cmake。",
),
("user", "测试怎么跑?"),
(
"assistant",
"运行测试:1) uv run pytest 跑全量测试 "
"2) uv run pytest tests/unit -x 只跑单元测试 "
"3) CI 会自动跑 lint + test,PR 合并前必须全绿。",
),
]
for role, content in messages:
run_async(session.add_message(role=role, content=content))
print(f" 添加了 {len(messages)} 条消息")
# ── 6. 沉淀记忆 ──
print("\n== 6. 沉淀记忆: commit session ==")
print(" 正在提取(开发流程、环境配置等)...")
client.commit_session(session.session_id)
print(" commit 完成")
time.sleep(2)
client.wait_processed(timeout=120)
print(" 记忆向量化完成")
# ── 7. 回顾自己的记忆 ──
print("\n== 7. 回顾记忆: '本地开发环境搭建' ==")
results = client.find(query="本地开发环境搭建步骤", limit=3)
memories = results.get("memories", [])
if memories:
print(" 记忆:")
for index, memory in enumerate(memories, 1):
description = (
memory.get("abstract")
or memory.get("overview")
or memory.get("uri", "")
)
print(f" {index}. [{memory.get('score', 0.0):.3f}] {description[:150]}")
resources = results.get("resources", [])
if resources:
print(" 资源:")
for index, resource in enumerate(resources, 1):
print(
f" {index}. [{resource.get('score', 0.0):.3f}] "
f"{resource['uri']}"
)
# ── 8. 带会话上下文的搜索 ──
print("\n== 8. 带上下文搜索: '还有什么注意事项' ==")
results = client.search(
query="还有什么需要注意的事项",
session_id=session.session_id,
limit=3,
)
resources = results.get("resources", [])
if resources:
for index, resource in enumerate(resources, 1):
print(
f" {index}. [{resource.get('score', 0.0):.3f}] "
f"{resource['uri']}"
)
memories = results.get("memories", [])
if memories:
for index, memory in enumerate(memories, 1):
description = (
memory.get("abstract")
or memory.get("overview")
or memory.get("uri", "")
)
print(f" {index}. [{memory.get('score', 0.0):.3f}] {description[:100]}")
print("\nBob 流程完成")
finally:
client.close()
if __name__ == "__main__":
main()