From b76afe23bfe762bdec1bdfbde50834ea98d536cc Mon Sep 17 00:00:00 2001 From: Max Date: Wed, 23 Jul 2025 17:07:38 +0800 Subject: [PATCH] Add Knowledge Base configuration and integration with GraphRag - Introduced a new configuration structure for the Knowledge Base, supporting vector and graph database configurations. - Implemented JSON parsing methods for loading configurations from files and converting them to JSON format. - Enhanced the Knowledge Base instance to integrate with GraphRag, allowing for dynamic configuration of vector and graph stores. - Added feature detection capabilities to determine available functionalities based on the current configuration. - Updated the Knowledge Base loading process to read from a specified configuration file, improving flexibility and usability. --- data/bindata.go | 246 ++++++++++++--------- go.mod | 9 + go.sum | 17 ++ kb/config.go | 196 +++++++++++++++++ kb/config_test.go | 375 +++++++++++++++++++++++++++++++++ kb/kb.go | 62 +++++- kb/types.go | 195 ++++++++++++++++- yao/stores/kb/cache.lru.yao | 13 ++ yao/stores/kb/store.badger.yao | 13 ++ 9 files changed, 1022 insertions(+), 104 deletions(-) create mode 100644 kb/config_test.go create mode 100644 yao/stores/kb/cache.lru.yao create mode 100644 yao/stores/kb/store.badger.yao diff --git a/data/bindata.go b/data/bindata.go index 9c304d2a..0c53417e 100644 --- a/data/bindata.go +++ b/data/bindata.go @@ -95,6 +95,8 @@ // .tmp/data/yao/stores/agent/cache.lru.yao // .tmp/data/yao/stores/agent/memory.badger.yao // .tmp/data/yao/stores/cache.lru.yao +// .tmp/data/yao/stores/kb/cache.lru.yao +// .tmp/data/yao/stores/kb/store.badger.yao // .tmp/data/yao/stores/oauth/cache.lru.yao // .tmp/data/yao/stores/oauth/client.badger.yao // .tmp/data/yao/stores/oauth/store.badger.yao @@ -277,7 +279,7 @@ func cuiSetupIndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "cui/setup/index.html", size: 10, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "cui/setup/index.html", size: 10, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -297,7 +299,7 @@ func cuiV09IndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "cui/v0.9/index.html", size: 13, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "cui/v0.9/index.html", size: 13, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -317,7 +319,7 @@ func cuiV10IndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "cui/v1.0/index.html", size: 49, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "cui/v1.0/index.html", size: 49, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -337,7 +339,7 @@ func cuiV10Layouts__indexAsyncJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "cui/v1.0/layouts__index.async.js", size: 71, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "cui/v1.0/layouts__index.async.js", size: 71, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -357,7 +359,7 @@ func cuiV10UmiJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "cui/v1.0/umi.js", size: 71, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "cui/v1.0/umi.js", size: 71, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -377,7 +379,7 @@ func initEnv() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.env", size: 219, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.env", size: 219, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -397,7 +399,7 @@ func initVscodeSettingsJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/settings.json", size: 4666, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/settings.json", size: 4666, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -417,7 +419,7 @@ func initVscodeTypesRuntimeConsoleDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/console.d.ts", size: 221, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/console.d.ts", size: 221, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -437,7 +439,7 @@ func initVscodeTypesRuntimeExceptionDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/exception.d.ts", size: 738, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/exception.d.ts", size: 738, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -457,7 +459,7 @@ func initVscodeTypesRuntimeFsDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/fs.d.ts", size: 8554, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/fs.d.ts", size: 8554, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -477,7 +479,7 @@ func initVscodeTypesRuntimeGlobalDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/global.d.ts", size: 1759, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/global.d.ts", size: 1759, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -497,7 +499,7 @@ func initVscodeTypesRuntimeHttpDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/http.d.ts", size: 6179, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/http.d.ts", size: 6179, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -517,7 +519,7 @@ func initVscodeTypesRuntimeIoDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/io.d.ts", size: 587, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/io.d.ts", size: 587, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -537,7 +539,7 @@ func initVscodeTypesRuntimeLogDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/log.d.ts", size: 1692, mode: os.FileMode(493), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/log.d.ts", size: 1692, mode: os.FileMode(493), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -557,7 +559,7 @@ func initVscodeTypesRuntimeNeoDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/neo.d.ts", size: 3750, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/neo.d.ts", size: 3750, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -577,7 +579,7 @@ func initVscodeTypesRuntimeProcessFsDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/process/fs.d.ts", size: 11133, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/process/fs.d.ts", size: 11133, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -597,7 +599,7 @@ func initVscodeTypesRuntimeProcessHttpDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/process/http.d.ts", size: 5653, mode: os.FileMode(493), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/process/http.d.ts", size: 5653, mode: os.FileMode(493), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -617,7 +619,7 @@ func initVscodeTypesRuntimeProcessModelDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/process/model.d.ts", size: 6656, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/process/model.d.ts", size: 6656, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -637,7 +639,7 @@ func initVscodeTypesRuntimeProcessDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/process.d.ts", size: 23165, mode: os.FileMode(493), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/process.d.ts", size: 23165, mode: os.FileMode(493), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -657,7 +659,7 @@ func initVscodeTypesRuntimeQueryDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/query.d.ts", size: 6124, mode: os.FileMode(493), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/query.d.ts", size: 6124, mode: os.FileMode(493), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -677,7 +679,7 @@ func initVscodeTypesRuntimeStoreDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/store.d.ts", size: 2251, mode: os.FileMode(493), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/store.d.ts", size: 2251, mode: os.FileMode(493), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -697,7 +699,7 @@ func initVscodeTypesRuntimeSuiDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/sui.d.ts", size: 1713, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/sui.d.ts", size: 1713, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -717,7 +719,7 @@ func initVscodeTypesRuntimeTimeDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime/time.d.ts", size: 711, mode: os.FileMode(493), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime/time.d.ts", size: 711, mode: os.FileMode(493), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -737,7 +739,7 @@ func initVscodeTypesRuntimeDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/runtime.d.ts", size: 424, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/runtime.d.ts", size: 424, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -757,7 +759,7 @@ func initVscodeTypesSuiDTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/.vscode/types/sui.d.ts", size: 8931, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/.vscode/types/sui.d.ts", size: 8931, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -777,7 +779,7 @@ func initAppYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/app.yao", size: 3115, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/app.yao", size: 3115, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -797,7 +799,7 @@ func initDataReadmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/README.md", size: 41, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/README.md", size: 41, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -817,7 +819,7 @@ func initDataTemplatesDefault__assetsReadmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/__assets/README.md", size: 33, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/__assets/README.md", size: 33, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -837,7 +839,7 @@ func initDataTemplatesDefault__assetsImagesIconsAppPng() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/__assets/images/icons/app.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/__assets/images/icons/app.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -857,7 +859,7 @@ func initDataTemplatesDefault__assetsImagesLogosLogo_colorSvg() (*asset, error) return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/__assets/images/logos/logo_color.svg", size: 2909, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/__assets/images/logos/logo_color.svg", size: 2909, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -877,7 +879,7 @@ func initDataTemplatesDefault__assetsImagesLogosWordmarkSvg() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/__assets/images/logos/wordmark.svg", size: 3615, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/__assets/images/logos/wordmark.svg", size: 3615, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -897,7 +899,7 @@ func initDataTemplatesDefault__dataJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/__data.json", size: 30, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/__data.json", size: 30, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -917,7 +919,7 @@ func initDataTemplatesDefault__documentHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/__document.html", size: 492, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/__document.html", size: 492, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -937,7 +939,7 @@ func initDataTemplatesDefaultIndexIndexCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/index/index.css", size: 2896, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/index/index.css", size: 2896, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -957,7 +959,7 @@ func initDataTemplatesDefaultIndexIndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/index/index.html", size: 2361, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/index/index.html", size: 2361, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -977,7 +979,7 @@ func initDataTemplatesDefaultIndexIndexJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/data/templates/default/index/index.json", size: 31, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/data/templates/default/index/index.json", size: 31, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -997,7 +999,7 @@ func initDbReadmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/db/README.md", size: 84, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/db/README.md", size: 84, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1017,7 +1019,7 @@ func initFlowsMenuFlowYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/flows/menu.flow.yao", size: 813, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/flows/menu.flow.yao", size: 813, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1037,7 +1039,7 @@ func initFormsAccountFormYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/forms/account.form.yao", size: 1194, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/forms/account.form.yao", size: 1194, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1057,7 +1059,7 @@ func initIconsAppIcns() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/icons/app.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/icons/app.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1077,7 +1079,7 @@ func initIconsAppIco() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/icons/app.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/icons/app.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1097,7 +1099,7 @@ func initIconsAppPng() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/icons/app.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/icons/app.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1117,7 +1119,7 @@ func initLoginsAdminLoginYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/logins/admin.login.yao", size: 302, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/logins/admin.login.yao", size: 302, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1137,7 +1139,7 @@ func initLogsReadmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/logs/README.md", size: 28, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/logs/README.md", size: 28, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1157,7 +1159,7 @@ func initModelsAdminUserModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/models/admin/user.mod.yao", size: 6416, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/models/admin/user.mod.yao", size: 6416, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1177,7 +1179,7 @@ func initModelsTestsPetModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/models/tests/pet.mod.yao", size: 525, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/models/tests/pet.mod.yao", size: 525, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1197,7 +1199,7 @@ func initNeoNeoYml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/neo/neo.yml", size: 724, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/neo/neo.yml", size: 724, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1217,7 +1219,7 @@ func initPublicReadmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/README.md", size: 108, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/README.md", size: 108, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1237,7 +1239,7 @@ func initPublicAssetsReadmeMd() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/assets/README.md", size: 33, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/assets/README.md", size: 33, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1257,7 +1259,7 @@ func initPublicAssetsImagesIconsAppPng() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/assets/images/icons/app.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/assets/images/icons/app.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1277,7 +1279,7 @@ func initPublicAssetsImagesLogosLogo_colorSvg() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/assets/images/logos/logo_color.svg", size: 2909, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/assets/images/logos/logo_color.svg", size: 2909, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1297,7 +1299,7 @@ func initPublicAssetsImagesLogosWordmarkSvg() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/assets/images/logos/wordmark.svg", size: 3615, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/assets/images/logos/wordmark.svg", size: 3615, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1317,7 +1319,7 @@ func initPublicAssetsLibsuiMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/assets/libsui.min.js", size: 12569, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/assets/libsui.min.js", size: 12569, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1337,7 +1339,7 @@ func initPublicAssetsLibsuiMinJsMap() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/assets/libsui.min.js.map", size: 38553, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/assets/libsui.min.js.map", size: 38553, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1357,7 +1359,7 @@ func initPublicIndexCfg() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/index.cfg", size: 85, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/index.cfg", size: 85, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1377,7 +1379,7 @@ func initPublicIndexSui() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/public/index.sui", size: 5682, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/public/index.sui", size: 5682, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1397,7 +1399,7 @@ func initScriptsAccountTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/scripts/account.ts", size: 2521, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/scripts/account.ts", size: 2521, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1417,7 +1419,7 @@ func initScriptsAiNeoTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/scripts/ai/neo.ts", size: 375, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/scripts/ai/neo.ts", size: 375, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1437,7 +1439,7 @@ func initScriptsTestsTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/scripts/tests.ts", size: 1044, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/scripts/tests.ts", size: 1044, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1457,7 +1459,7 @@ func initScriptsUtilsTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/scripts/utils.ts", size: 1230, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/scripts/utils.ts", size: 1230, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1477,7 +1479,7 @@ func initSuisWebSuiYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/suis/web.sui.yao", size: 675, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/suis/web.sui.yao", size: 675, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1497,7 +1499,7 @@ func initTablesAccountTabYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/tables/account.tab.yao", size: 5597, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/tables/account.tab.yao", size: 5597, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1517,7 +1519,7 @@ func initTsconfigJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "init/tsconfig.json", size: 178, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "init/tsconfig.json", size: 178, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1537,7 +1539,7 @@ func libsuiAgentTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "libsui/agent.ts", size: 15267, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "libsui/agent.ts", size: 15267, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1557,7 +1559,7 @@ func libsuiIndexTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "libsui/index.ts", size: 13049, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "libsui/index.ts", size: 13049, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1577,7 +1579,7 @@ func libsuiUtilsTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "libsui/utils.ts", size: 5959, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "libsui/utils.ts", size: 5959, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1597,7 +1599,7 @@ func libsuiYaoTs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "libsui/yao.ts", size: 4338, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "libsui/yao.ts", size: 4338, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1617,7 +1619,7 @@ func publicIndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "public/index.html", size: 11, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "public/index.html", size: 11, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1637,7 +1639,7 @@ func uiIndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "ui/index.html", size: 11, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "ui/index.html", size: 11, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1657,7 +1659,7 @@ func yaoDataIcons404Png() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/data/icons/404.png", size: 9342, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1677,7 +1679,7 @@ func yaoDataIconsIconIcns() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/data/icons/icon.icns", size: 67465, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1697,7 +1699,7 @@ func yaoDataIconsIconIco() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/data/icons/icon.ico", size: 54993, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1717,7 +1719,7 @@ func yaoDataIconsIconPng() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/data/icons/icon.png", size: 34558, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1737,7 +1739,7 @@ func yaoDataIndexHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/data/index.html", size: 282, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1757,7 +1759,7 @@ func yaoFieldsModelTransJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/fields/model.trans.json", size: 14938, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/fields/model.trans.json", size: 14938, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1777,7 +1779,7 @@ func yaoLangsEnUsJson() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/langs/en-US.json", size: 66, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1797,7 +1799,7 @@ func yaoLangsZhCnGlobalYml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/langs/zh-cn/global.yml", size: 1762, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/langs/zh-cn/global.yml", size: 1762, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1817,7 +1819,7 @@ func yaoLangsZhCnLoginsAdminLoginYml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/langs/zh-cn/logins/admin.login.yml", size: 94, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/langs/zh-cn/logins/admin.login.yml", size: 94, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1837,7 +1839,7 @@ func yaoLangsZhCnLoginsUserLoginYml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/langs/zh-cn/logins/user.login.yml", size: 90, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/langs/zh-cn/logins/user.login.yml", size: 90, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1857,7 +1859,7 @@ func yaoLangsZhHkGlobalYml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/langs/zh-hk/global.yml", size: 1762, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/langs/zh-hk/global.yml", size: 1762, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1877,7 +1879,7 @@ func yaoLangsZhHkLoginsAdminLoginYml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/langs/zh-hk/logins/admin.login.yml", size: 94, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/langs/zh-hk/logins/admin.login.yml", size: 94, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1897,7 +1899,7 @@ func yaoLangsZhHkLoginsUserLoginYml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/langs/zh-hk/logins/user.login.yml", size: 90, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/langs/zh-hk/logins/user.login.yml", size: 90, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1917,7 +1919,7 @@ func yaoModelsAssistantModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/assistant.mod.yao", size: 4114, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/assistant.mod.yao", size: 4114, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1937,7 +1939,7 @@ func yaoModelsAttachmentModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/attachment.mod.yao", size: 3264, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/attachment.mod.yao", size: 3264, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1957,7 +1959,7 @@ func yaoModelsAuditModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/audit.mod.yao", size: 5588, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/audit.mod.yao", size: 5588, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1977,7 +1979,7 @@ func yaoModelsChatModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/chat.mod.yao", size: 1444, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/chat.mod.yao", size: 1444, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1997,7 +1999,7 @@ func yaoModelsConfigModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/config.mod.yao", size: 1649, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/config.mod.yao", size: 1649, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2017,7 +2019,7 @@ func yaoModelsDslModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/dsl.mod.yao", size: 3806, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/dsl.mod.yao", size: 3806, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2037,7 +2039,7 @@ func yaoModelsHistoryModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/history.mod.yao", size: 2902, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/history.mod.yao", size: 2902, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2057,7 +2059,7 @@ func yaoModelsKbModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/kb.mod.yao", size: 2881, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/kb.mod.yao", size: 2881, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2077,7 +2079,7 @@ func yaoModelsUserModYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/models/user.mod.yao", size: 6775, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/models/user.mod.yao", size: 6775, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2097,7 +2099,7 @@ func yaoReleaseAppYaz() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/release/app.yaz", size: 181682, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/release/app.yaz", size: 181682, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2117,7 +2119,7 @@ func yaoStoresAgentCacheLruYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/stores/agent/cache.lru.yao", size: 301, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/stores/agent/cache.lru.yao", size: 301, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2137,7 +2139,7 @@ func yaoStoresAgentMemoryBadgerYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/stores/agent/memory.badger.yao", size: 352, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/stores/agent/memory.badger.yao", size: 352, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2157,7 +2159,47 @@ func yaoStoresCacheLruYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/stores/cache.lru.yao", size: 285, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/stores/cache.lru.yao", size: 285, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _yaoStoresKbCacheLruYao = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x90\x31\x4f\xc4\x30\x0c\x85\xf7\xfe\x8a\x27\xcf\xb7\x94\x09\x3a\xc2\x08\x13\x88\x09\x31\xb8\xad\xef\x88\x2e\x17\x57\x8e\x2b\x54\xd0\xfd\x77\xe4\x54\x2c\x4c\x4c\x49\x9e\x3e\x7d\xf1\xf3\x77\x07\x50\xe6\x51\x32\x0d\xa0\xc7\xa2\x9f\x59\xe6\x93\xe0\x9e\xab\xe0\x81\xa7\x0f\xc1\x8b\xab\x09\x1d\x02\x9c\xa5\x4e\x96\x16\x4f\x5a\x02\x7f\x7a\x7e\xc5\xd4\x98\x1a\x0c\x8e\x6a\xf8\xa3\x70\xb9\x2c\x6a\x6c\x1b\x66\x76\xde\x2d\xce\xa7\x4a\x03\xde\xe8\x3c\xd2\x01\xd4\x0c\x71\xc9\xb6\xc6\xe1\x7a\x96\x42\xef\x0d\x35\xe1\x59\x4b\xde\x68\xc0\x91\x73\x95\x16\x8e\x6b\xca\x9e\x62\x02\xb7\x75\x8f\xaa\x9a\xd3\x80\xbe\x6f\xaf\xc2\x17\xf9\x4f\x1d\xdf\x96\xc6\xb5\x8f\x23\xd0\xdf\x6a\xb1\x96\xd0\xa6\xaf\x00\x6e\xfb\xbb\x9b\x0e\xb8\x76\xd7\xee\x27\x00\x00\xff\xff\xd2\xb4\xa0\x9a\x30\x01\x00\x00") + +func yaoStoresKbCacheLruYaoBytes() ([]byte, error) { + return bindataRead( + _yaoStoresKbCacheLruYao, + "yao/stores/kb/cache.lru.yao", + ) +} + +func yaoStoresKbCacheLruYao() (*asset, error) { + bytes, err := yaoStoresKbCacheLruYaoBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "yao/stores/kb/cache.lru.yao", size: 304, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _yaoStoresKbStoreBadgerYao = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x90\x31\x6b\xc3\x30\x10\x85\x77\xff\x8a\xc7\xcd\x29\x69\x57\x6f\x0e\xd9\x3a\x18\xda\x2c\xa5\x94\x70\xaa\x2e\xae\x89\x2a\x19\xdd\x85\x12\x8c\xff\x7b\x91\x4c\x28\x74\xca\x76\xf7\x78\xdf\x93\xde\xcd\x0d\x40\x81\x9d\x04\x6a\x41\xcf\x31\xfd\x04\xf1\x83\x60\xc7\x2a\xd8\xb3\x31\x5e\x2d\x65\xa1\x4d\xf1\x79\xd1\xcf\x3c\x4e\x36\xa6\x58\xdc\x3b\xf6\x83\xe4\x07\xc7\x2a\x1e\x93\x64\x1d\xd5\x24\x1a\xb4\x10\x38\xa5\x8c\x7f\x79\x9e\x8d\xd7\x24\xe3\x41\xa9\xc5\x3b\x9d\x1d\x6d\x40\x7f\x70\xd9\x5c\xcd\x2d\x53\x05\x3e\x2a\x91\x85\x7d\x8a\xe1\x4a\x2d\x4e\x1c\x54\xaa\xe8\x2e\x63\xb0\xb1\x7c\xc6\xf2\x65\x95\x34\x65\xa3\x16\x4f\x8f\x75\x8b\xfc\x2d\x77\x14\xb3\xeb\x54\x6d\xb7\x97\x8b\x96\x6e\x3d\xcb\x89\x00\x9a\xd8\xbe\x8a\x67\x9e\xf1\xd6\xf5\xc7\x7d\x77\xe8\x8e\x2f\x7d\x7f\xc0\xb2\x6c\x6b\x63\xdd\x9e\xdd\x3a\x51\x03\x2c\xcd\xd2\xfc\x06\x00\x00\xff\xff\x7a\xea\x44\x5c\x5d\x01\x00\x00") + +func yaoStoresKbStoreBadgerYaoBytes() ([]byte, error) { + return bindataRead( + _yaoStoresKbStoreBadgerYao, + "yao/stores/kb/store.badger.yao", + ) +} + +func yaoStoresKbStoreBadgerYao() (*asset, error) { + bytes, err := yaoStoresKbStoreBadgerYaoBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "yao/stores/kb/store.badger.yao", size: 349, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2177,7 +2219,7 @@ func yaoStoresOauthCacheLruYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/stores/oauth/cache.lru.yao", size: 301, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/stores/oauth/cache.lru.yao", size: 301, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2197,7 +2239,7 @@ func yaoStoresOauthClientBadgerYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/stores/oauth/client.badger.yao", size: 352, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/stores/oauth/client.badger.yao", size: 352, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2217,7 +2259,7 @@ func yaoStoresOauthStoreBadgerYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/stores/oauth/store.badger.yao", size: 376, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/stores/oauth/store.badger.yao", size: 376, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2237,7 +2279,7 @@ func yaoStoresStoreBadgerYao() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "yao/stores/store.badger.yao", size: 341, mode: os.FileMode(420), modTime: time.Unix(1752984198, 0)} + info := bindataFileInfo{name: "yao/stores/store.badger.yao", size: 341, mode: os.FileMode(420), modTime: time.Unix(1753261259, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -2389,6 +2431,8 @@ var _bindata = map[string]func() (*asset, error){ "yao/stores/agent/cache.lru.yao": yaoStoresAgentCacheLruYao, "yao/stores/agent/memory.badger.yao": yaoStoresAgentMemoryBadgerYao, "yao/stores/cache.lru.yao": yaoStoresCacheLruYao, + "yao/stores/kb/cache.lru.yao": yaoStoresKbCacheLruYao, + "yao/stores/kb/store.badger.yao": yaoStoresKbStoreBadgerYao, "yao/stores/oauth/cache.lru.yao": yaoStoresOauthCacheLruYao, "yao/stores/oauth/client.badger.yao": yaoStoresOauthClientBadgerYao, "yao/stores/oauth/store.badger.yao": yaoStoresOauthStoreBadgerYao, @@ -2635,6 +2679,10 @@ var _bintree = &bintree{nil, map[string]*bintree{ "memory.badger.yao": {yaoStoresAgentMemoryBadgerYao, map[string]*bintree{}}, }}, "cache.lru.yao": {yaoStoresCacheLruYao, map[string]*bintree{}}, + "kb": {nil, map[string]*bintree{ + "cache.lru.yao": {yaoStoresKbCacheLruYao, map[string]*bintree{}}, + "store.badger.yao": {yaoStoresKbStoreBadgerYao, map[string]*bintree{}}, + }}, "oauth": {nil, map[string]*bintree{ "cache.lru.yao": {yaoStoresOauthCacheLruYao, map[string]*bintree{}}, "client.badger.yao": {yaoStoresOauthClientBadgerYao, map[string]*bintree{}}, diff --git a/go.mod b/go.mod index 2a2eb722..0db530f3 100644 --- a/go.mod +++ b/go.mod @@ -90,6 +90,9 @@ require ( github.com/hashicorp/go-plugin v1.6.3 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect + github.com/hhrutter/lzw v1.0.0 // indirect + github.com/hhrutter/pkcs7 v0.2.0 // indirect + github.com/hhrutter/tiff v1.0.2 // indirect github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmoiron/sqlx v1.4.0 // indirect @@ -100,17 +103,22 @@ require ( github.com/mark3labs/mcp-go v0.32.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-sqlite3 v1.14.28 // indirect github.com/miekg/dns v1.1.66 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect + github.com/neo4j/neo4j-go-driver/v5 v5.28.1 // indirect github.com/oklog/run v1.1.0 // indirect + github.com/pdfcpu/pdfcpu v0.11.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/qdrant/go-client v1.14.0 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.4 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -149,6 +157,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect google.golang.org/grpc v1.72.1 // indirect google.golang.org/protobuf v1.36.6 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) // go env -w GOPRIVATE=github.com/yaoapp/* diff --git a/go.sum b/go.sum index 2a0f960d..48e03ff4 100644 --- a/go.sum +++ b/go.sum @@ -147,6 +147,12 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= +github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0= +github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo= +github.com/hhrutter/pkcs7 v0.2.0 h1:i4HN2XMbGQpZRnKBLsUwO3dSckzgX142TNqY/KfXg+I= +github.com/hhrutter/pkcs7 v0.2.0/go.mod h1:aEzKz0+ZAlz7YaEMY47jDHL14hVWD6iXt0AgqgAvWgE= +github.com/hhrutter/tiff v1.0.2 h1:7H3FQQpKu/i5WaSChoD1nnJbGx4MxU5TlNqqpxw55z8= +github.com/hhrutter/tiff v1.0.2/go.mod h1:pcOeuK5loFUE7Y/WnzGw20YxUdnqjY1P0Jlcieb/cCw= github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519 h1:nqAlWFEdqI0ClbTDrhDvE/8LeQ4pftrqKUX9w5k0j3s= github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -191,6 +197,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= @@ -205,6 +213,8 @@ github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8 github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ= github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= +github.com/neo4j/neo4j-go-driver/v5 v5.28.1 h1:RKWQW7wTgYAY2fU9S+9LaJ9OwRPbRc0I17tlT7nDmAY= +github.com/neo4j/neo4j-go-driver/v5 v5.28.1/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= @@ -215,8 +225,12 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/pdfcpu/pdfcpu v0.11.0 h1:mL18Y3hSHzSezmnrzA21TqlayBOXuAx7BUzzZyroLGM= +github.com/pdfcpu/pdfcpu v0.11.0/go.mod h1:F1ca4GIVFdPtmgvIdvXAycAm88noyNxZwzr9CpTy+Mw= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkoukk/tiktoken-go v0.1.7 h1:qOBHXX4PHtvIvmOtyg1EeKlwFRiMKAcoMp4Q+bLQDmw= github.com/pkoukk/tiktoken-go v0.1.7/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -230,6 +244,9 @@ github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7 github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00= github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= diff --git a/kb/config.go b/kb/config.go index edfaf336..8e67fe09 100644 --- a/kb/config.go +++ b/kb/config.go @@ -1,3 +1,199 @@ package kb +import ( + "encoding/json" + "os" + + "github.com/yaoapp/gou/graphrag" + "github.com/yaoapp/gou/graphrag/graph/neo4j" + "github.com/yaoapp/gou/graphrag/types" + "github.com/yaoapp/gou/graphrag/vector/qdrant" + "github.com/yaoapp/gou/store" + "github.com/yaoapp/kun/log" +) + // Config parses the Knowledge Base configuration + +// ParseConfigFromJSON parses config from JSON bytes +func ParseConfigFromJSON(data []byte) (*Config, error) { + var config Config + if err := json.Unmarshal(data, &config); err != nil { + return nil, err + } + return &config, nil +} + +// ParseConfigFromFile parses config from JSON file +func ParseConfigFromFile(filename string) (*Config, error) { + data, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + return ParseConfigFromJSON(data) +} + +// ToJSON converts config to JSON bytes +func (c *Config) ToJSON() ([]byte, error) { + return json.MarshalIndent(c, "", " ") +} + +// GraphRagConfig converts KB config to GraphRag config +func (c *Config) GraphRagConfig() (*graphrag.Config, error) { + + config := &graphrag.Config{ + Logger: log.StandardLogger(), + System: "__yao_kb_system", // Default system collection name + Vector: nil, + Graph: nil, + Store: nil, + } + + // Configure Vector Store (required) + vectorStore, err := c.createVectorStore() + if err != nil { + return nil, err + } + config.Vector = vectorStore + + // Configure Graph Store (optional) + if c.Graph != nil { + graphStore, err := c.createGraphStore() + if err != nil { + return nil, err + } + config.Graph = graphStore + } + + // Configure Store + storeName := c.getStoreName() + kvStore, err := store.Get(storeName) + if err != nil { + return nil, err + } + config.Store = kvStore + return config, nil +} + +// getStoreName returns the store name, using default if not configured +func (c *Config) getStoreName() string { + if c.Store != "" { + return c.Store + } + return "__yao.kb.store" +} + +// createVectorStore creates a vector store from config +func (c *Config) createVectorStore() (types.VectorStore, error) { + switch c.Vector.Driver { + case "qdrant": + // Convert config to VectorStoreConfig + vectorConfig, err := c.toVectorStoreConfig() + if err != nil { + return nil, err + } + return qdrant.NewStoreWithConfig(vectorConfig), nil + default: + return nil, nil + } +} + +// createGraphStore creates a graph store from config +func (c *Config) createGraphStore() (types.GraphStore, error) { + switch c.Graph.Driver { + case "neo4j": + // Convert config to GraphStoreConfig + graphConfig, err := c.toGraphStoreConfig() + if err != nil { + return nil, err + } + return neo4j.NewStoreWithConfig(graphConfig), nil + default: + return nil, nil + } +} + +// toVectorStoreConfig converts the vector config to VectorStoreConfig +func (c *Config) toVectorStoreConfig() (types.VectorStoreConfig, error) { + // Convert map[string]interface{} to types.VectorStoreConfig via JSON + jsonData, err := json.Marshal(c.Vector.Config) + if err != nil { + return types.VectorStoreConfig{}, err + } + + var config types.VectorStoreConfig + if err := json.Unmarshal(jsonData, &config); err != nil { + return types.VectorStoreConfig{}, err + } + + return config, nil +} + +// toGraphStoreConfig converts the graph config to GraphStoreConfig +func (c *Config) toGraphStoreConfig() (types.GraphStoreConfig, error) { + // Convert map[string]interface{} to types.GraphStoreConfig via JSON + jsonData, err := json.Marshal(c.Graph.Config) + if err != nil { + return types.GraphStoreConfig{}, err + } + + var config types.GraphStoreConfig + if err := json.Unmarshal(jsonData, &config); err != nil { + return types.GraphStoreConfig{}, err + } + + return config, nil +} + +// UnmarshalJSON implements json.Unmarshaler interface +func (c *Config) UnmarshalJSON(data []byte) error { + // Use alias type to avoid infinite recursion + raw := (*RawConfig)(c) + if err := json.Unmarshal(data, raw); err != nil { + return err + } + + // Compute features after parsing + c.Features = c.ComputeFeatures() + + return nil +} + +// MarshalJSON implements json.Marshaler interface +func (c *Config) MarshalJSON() ([]byte, error) { + // Use alias type for standard JSON marshaling (Features field is ignored) + raw := (*RawConfig)(c) + return json.Marshal(raw) +} + +// ComputeFeatures calculates available features based on current configuration +func (c *Config) ComputeFeatures() Features { + features := Features{} + + // Core features + features.GraphDatabase = c.Graph != nil + features.PDFProcessing = c.PDF != nil + features.VideoProcessing = c.FFmpeg != nil + + // File format support (based on converters) + converterMap := make(map[string]bool) + for _, provider := range c.Converters { + converterMap[provider.ID] = true + } + + features.PlainText = true // Plain text is always supported as a basic feature + features.OfficeDocuments = converterMap["__yao.office"] + features.OCRProcessing = converterMap["__yao.ocr"] + features.AudioTranscript = converterMap["__yao.whisper"] + features.ImageAnalysis = converterMap["__yao.vision"] + + // Advanced features + features.EntityExtraction = len(c.Extractors) > 0 + features.WebFetching = len(c.Fetchers) > 0 + features.CustomSearch = len(c.Searchers) > 0 + features.ResultReranking = len(c.Rerankers) > 0 + features.SegmentVoting = len(c.Votes) > 0 + features.SegmentWeighting = len(c.Weights) > 0 + features.SegmentScoring = len(c.Scores) > 0 + + return features +} diff --git a/kb/config_test.go b/kb/config_test.go new file mode 100644 index 00000000..a754bb28 --- /dev/null +++ b/kb/config_test.go @@ -0,0 +1,375 @@ +package kb + +import ( + "encoding/json" + "os" + "reflect" + "strings" + "testing" +) + +// Test data for configuration parsing +const testConfigJSON = `{ + "vector": { + "driver": "qdrant", + "config": { + "host": "127.0.0.1", + "port": 6333 + } + }, + "graph": { + "driver": "neo4j", + "config": { + "url": "neo4j://127.0.0.1:7686" + } + }, + "store": "test_store", + "pdf": { + "convert_tool": "pdftoppm", + "tool_path": "/usr/bin/pdftoppm" + }, + "ffmpeg": { + "ffmpeg_path": "/usr/bin/ffmpeg", + "ffprobe_path": "/usr/bin/ffprobe", + "enable_gpu": true + }, + "chunkings": [ + { + "id": "__yao.structured", + "label": "Document Structure", + "description": "Split text by document structure", + "default": true, + "options": [] + } + ], + "embeddings": [ + { + "id": "__yao.openai", + "label": "OpenAI", + "description": "OpenAI embeddings", + "default": true, + "options": [] + } + ], + "converters": [ + { + "id": "__yao.office", + "label": "Office Documents", + "description": "Process office documents", + "options": [] + }, + { + "id": "__yao.ocr", + "label": "OCR", + "description": "OCR processing", + "options": [] + } + ], + "extractors": [ + { + "id": "__yao.openai", + "label": "OpenAI Extractor", + "description": "Entity extraction", + "options": [] + } + ], + "fetchers": [ + { + "id": "__yao.http", + "label": "HTTP Fetcher", + "description": "Fetch from web", + "options": [] + } + ] +}` + +const minimalConfigJSON = `{ + "vector": { + "driver": "qdrant", + "config": {} + }, + "chunkings": [ + { + "id": "__yao.structured", + "label": "Document Structure", + "description": "Split text", + "options": [] + } + ], + "embeddings": [ + { + "id": "__yao.openai", + "label": "OpenAI", + "description": "OpenAI embeddings", + "options": [] + } + ] +}` + +func TestParseConfigFromJSON(t *testing.T) { + tests := []struct { + name string + json string + wantErr bool + }{ + { + name: "valid full config", + json: testConfigJSON, + wantErr: false, + }, + { + name: "valid minimal config", + json: minimalConfigJSON, + wantErr: false, + }, + { + name: "invalid json", + json: `{"invalid": json}`, + wantErr: true, + }, + { + name: "empty json", + json: `{}`, + wantErr: false, // Should parse but with empty fields + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + config, err := ParseConfigFromJSON([]byte(tt.json)) + if (err != nil) != tt.wantErr { + t.Errorf("ParseConfigFromJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr && config == nil { + t.Error("ParseConfigFromJSON() returned nil config without error") + } + }) + } +} + +func TestParseConfigFromFile(t *testing.T) { + // Create temporary test file + tmpFile, err := os.CreateTemp("", "test_config_*.json") + if err != nil { + t.Fatalf("Failed to create temp file: %v", err) + } + defer os.Remove(tmpFile.Name()) + + // Write test config to file + if _, err := tmpFile.WriteString(testConfigJSON); err != nil { + t.Fatalf("Failed to write test config: %v", err) + } + tmpFile.Close() + + // Test parsing from file + config, err := ParseConfigFromFile(tmpFile.Name()) + if err != nil { + t.Errorf("ParseConfigFromFile() error = %v", err) + return + } + if config == nil { + t.Error("ParseConfigFromFile() returned nil config") + return + } + + // Verify basic fields + if config.Vector.Driver != "qdrant" { + t.Errorf("Expected vector driver 'qdrant', got '%s'", config.Vector.Driver) + } + if config.Store != "test_store" { + t.Errorf("Expected store 'test_store', got '%s'", config.Store) + } + + // Test non-existent file + _, err = ParseConfigFromFile("non_existent_file.json") + if err == nil { + t.Error("Expected error for non-existent file, got nil") + } +} + +func TestConfig_ToJSON(t *testing.T) { + // Parse a config first + config, err := ParseConfigFromJSON([]byte(testConfigJSON)) + if err != nil { + t.Fatalf("Failed to parse test config: %v", err) + } + + // Convert back to JSON + jsonData, err := config.ToJSON() + if err != nil { + t.Errorf("ToJSON() error = %v", err) + return + } + + // Verify it's valid JSON + var testObj map[string]interface{} + if err := json.Unmarshal(jsonData, &testObj); err != nil { + t.Errorf("ToJSON() produced invalid JSON: %v", err) + } + + // Verify Features field is not included in JSON output + jsonStr := string(jsonData) + if strings.Contains(jsonStr, "features") || strings.Contains(jsonStr, "Features") { + t.Error("ToJSON() should not include Features field") + } +} + +func TestConfig_UnmarshalJSON(t *testing.T) { + var config Config + err := json.Unmarshal([]byte(testConfigJSON), &config) + if err != nil { + t.Errorf("UnmarshalJSON() error = %v", err) + return + } + + // Verify basic fields + if config.Vector.Driver != "qdrant" { + t.Errorf("Expected vector driver 'qdrant', got '%s'", config.Vector.Driver) + } + + // Verify Features are computed automatically + if !config.Features.GraphDatabase { + t.Error("Expected GraphDatabase feature to be true") + } + if !config.Features.PDFProcessing { + t.Error("Expected PDFProcessing feature to be true") + } + if !config.Features.VideoProcessing { + t.Error("Expected VideoProcessing feature to be true") + } +} + +func TestConfig_MarshalJSON(t *testing.T) { + config := &Config{ + Vector: VectorConfig{ + Driver: "qdrant", + Config: map[string]interface{}{"host": "localhost"}, + }, + Store: "test_store", + Features: Features{ + GraphDatabase: true, // This should not appear in JSON + }, + } + + jsonData, err := json.Marshal(config) + if err != nil { + t.Errorf("MarshalJSON() error = %v", err) + return + } + + // Verify Features field is not included + jsonStr := string(jsonData) + if strings.Contains(jsonStr, "features") || strings.Contains(jsonStr, "Features") { + t.Error("MarshalJSON() should not include Features field") + } + + // Verify other fields are included + if !strings.Contains(jsonStr, "qdrant") { + t.Error("MarshalJSON() should include vector driver") + } + if !strings.Contains(jsonStr, "test_store") { + t.Error("MarshalJSON() should include store") + } +} + +func TestConfig_ComputeFeatures(t *testing.T) { + tests := []struct { + name string + config *Config + expected Features + }{ + { + name: "full features config", + config: &Config{ + Graph: &GraphConfig{Driver: "neo4j"}, + PDF: &PDFConfig{ConvertTool: "pdftoppm"}, + FFmpeg: &FFmpegConfig{FFmpegPath: "/usr/bin/ffmpeg"}, + Converters: []*Provider{ + {ID: "__yao.office"}, + {ID: "__yao.ocr"}, + {ID: "__yao.whisper"}, + {ID: "__yao.vision"}, + }, + Extractors: []*Provider{{ID: "test"}}, + Fetchers: []*Provider{{ID: "test"}}, + Searchers: []*Provider{{ID: "test"}}, + Rerankers: []*Provider{{ID: "test"}}, + Votes: []*Provider{{ID: "test"}}, + Weights: []*Provider{{ID: "test"}}, + Scores: []*Provider{{ID: "test"}}, + }, + expected: Features{ + GraphDatabase: true, + PDFProcessing: true, + VideoProcessing: true, + PlainText: true, + OfficeDocuments: true, + OCRProcessing: true, + AudioTranscript: true, + ImageAnalysis: true, + EntityExtraction: true, + WebFetching: true, + CustomSearch: true, + ResultReranking: true, + SegmentVoting: true, + SegmentWeighting: true, + SegmentScoring: true, + }, + }, + { + name: "minimal config", + config: &Config{ + Graph: nil, + PDF: nil, + FFmpeg: nil, + }, + expected: Features{ + GraphDatabase: false, + PDFProcessing: false, + VideoProcessing: false, + PlainText: true, // Always supported + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.config.ComputeFeatures() + if !reflect.DeepEqual(result, tt.expected) { + t.Errorf("ComputeFeatures() = %+v, want %+v", result, tt.expected) + } + }) + } +} + +func TestRoundTrip(t *testing.T) { + // Parse config from JSON + originalConfig, err := ParseConfigFromJSON([]byte(testConfigJSON)) + if err != nil { + t.Fatalf("Failed to parse original config: %v", err) + } + + // Convert to JSON + jsonData, err := originalConfig.ToJSON() + if err != nil { + t.Fatalf("Failed to convert config to JSON: %v", err) + } + + // Parse again + roundTripConfig, err := ParseConfigFromJSON(jsonData) + if err != nil { + t.Fatalf("Failed to parse round-trip config: %v", err) + } + + // Compare key fields (Features will be recomputed, so they should match) + if originalConfig.Vector.Driver != roundTripConfig.Vector.Driver { + t.Errorf("Vector driver mismatch: %s != %s", originalConfig.Vector.Driver, roundTripConfig.Vector.Driver) + } + if originalConfig.Store != roundTripConfig.Store { + t.Errorf("Store mismatch: %s != %s", originalConfig.Store, roundTripConfig.Store) + } + if !reflect.DeepEqual(originalConfig.Features, roundTripConfig.Features) { + t.Errorf("Features mismatch: %+v != %+v", originalConfig.Features, roundTripConfig.Features) + } +} diff --git a/kb/kb.go b/kb/kb.go index 8abceb50..8ba9a8ca 100644 --- a/kb/kb.go +++ b/kb/kb.go @@ -1,11 +1,65 @@ package kb -import "github.com/yaoapp/gou/graphrag/types" +import ( + "path/filepath" + + "github.com/yaoapp/gou/application" + "github.com/yaoapp/gou/graphrag" + "github.com/yaoapp/gou/graphrag/types" + "github.com/yaoapp/kun/log" + "github.com/yaoapp/yao/config" +) // Instance is the GraphRag instance var Instance types.GraphRag = nil -// Load loads the GraphRag instance -func Load(config *Config) error { - return nil +// KnowledgeBase is the Knowledge Base instance +type KnowledgeBase struct { + Config *Config // Knowledge Base configuration + *graphrag.GraphRag +} + +// Load loads the GraphRag instance +func Load(appConfig config.Config) (*KnowledgeBase, error) { + + configPath := filepath.Join("kb", "kb.yao") + exists, err := application.App.Exists(configPath) + if err != nil { + return nil, err + } + if !exists { + log.Warn("[Knowledge Base] kb.yao file not found, skip loading knowledge base") + return nil, nil + } + + // Parse the configuration + var config Config + raw, err := application.App.Read(filepath.Join("kb", "kb.yao")) + if err != nil { + return nil, err + } + + err = application.Parse("kb", raw, &config) + if err != nil { + return nil, err + } + + // Create the GraphRag config + graphRagConfig, err := config.GraphRagConfig() + if err != nil { + return nil, err + } + + // Create the GraphRag instance + graphRag, err := graphrag.New(graphRagConfig) + if err != nil { + return nil, err + } + + // Set the instance + instance := &KnowledgeBase{Config: &config, GraphRag: graphRag} + + // Set the instance to the global variable + Instance = instance + return instance, nil } diff --git a/kb/types.go b/kb/types.go index 4ab22421..a4018ce1 100644 --- a/kb/types.go +++ b/kb/types.go @@ -1,4 +1,197 @@ package kb +// Features represents the available features based on current configuration +type Features struct { + // Core features + GraphDatabase bool // Graph database support (neo4j) + PDFProcessing bool // PDF text extraction + VideoProcessing bool // Video/audio processing (ffmpeg) + + // File format support (based on converters) + PlainText bool // Plain text files (.txt, .md) + OfficeDocuments bool // Office documents (.docx, .pptx) + OCRProcessing bool // Text recognition from images and PDFs + AudioTranscript bool // Audio transcription + ImageAnalysis bool // Image content analysis + + // Advanced features + EntityExtraction bool // Entity and relationship extraction + WebFetching bool // Web URL fetching + CustomSearch bool // Custom search providers + ResultReranking bool // Search result reranking + SegmentVoting bool // Segment voting system + SegmentWeighting bool // Segment weighting system + SegmentScoring bool // Segment scoring system +} + // Config is the configuration for the Knowledge Base -type Config struct{} +type Config struct { + // Vector Database configuration (Required) + Vector VectorConfig `json:"vector" yaml:"vector"` + + // Graph Database configuration (Optional, if not set, graph feature will be disabled) + Graph *GraphConfig `json:"graph,omitempty" yaml:"graph"` + + // KV store name (Optional with default value) + Store string `json:"store,omitempty" yaml:"store"` // Default: "__yao.kb.store" + + // PDF parser configuration (Optional) + PDF *PDFConfig `json:"pdf,omitempty" yaml:"pdf"` + + // FFmpeg configuration (Optional) + FFmpeg *FFmpegConfig `json:"ffmpeg,omitempty" yaml:"ffmpeg"` + + // Concurrency limits for task processing (Optional) + Limits *LimitsConfig `json:"limits,omitempty" yaml:"limits"` + + // Provider configurations + Chunkings []*Provider `json:"chunkings" yaml:"chunkings"` // Text splitting providers (Required - at least one) + Embeddings []*Provider `json:"embeddings" yaml:"embeddings"` // Text vectorization providers (Required - at least one) + Converters []*Provider `json:"converters,omitempty" yaml:"converters"` // File processing converters (Optional) + Extractors []*Provider `json:"extractors,omitempty" yaml:"extractors"` // Entity and relationship extractors (Optional) + Fetchers []*Provider `json:"fetchers,omitempty" yaml:"fetchers"` // File fetchers (Optional) + Searchers []*Provider `json:"searchers,omitempty" yaml:"searchers"` // Search providers (Optional) + Rerankers []*Provider `json:"rerankers,omitempty" yaml:"rerankers"` // Reranking providers (Optional) + Votes []*Provider `json:"votes,omitempty" yaml:"votes"` // Voting providers (Optional) + Weights []*Provider `json:"weights,omitempty" yaml:"weights"` // Weighting providers (Optional) + Scores []*Provider `json:"scores,omitempty" yaml:"scores"` // Scoring providers (Optional) + + // Feature flags (computed during parsing, not serialized) + Features Features `json:"-"` +} + +// VectorConfig represents vector database configuration +type VectorConfig struct { + Driver string `json:"driver" yaml:"driver"` // Required, currently only support "qdrant" + Config map[string]interface{} `json:"config" yaml:"config"` // Driver-specific configuration +} + +// GraphConfig represents graph database configuration +type GraphConfig struct { + Driver string `json:"driver" yaml:"driver"` // Required, currently only support "neo4j" + Config map[string]interface{} `json:"config" yaml:"config"` // Driver-specific configuration + SeparateDatabase bool `json:"separate_database,omitempty" yaml:"separate_database"` // Optional, for neo4j enterprise edition only +} + +// PDFConfig represents PDF parser configuration +type PDFConfig struct { + ConvertTool string `json:"convert_tool" yaml:"convert_tool"` // Required, pdftoppm/pdf2image/convert(imagemagick) + ToolPath string `json:"tool_path" yaml:"tool_path"` // Required, path to the tool +} + +// FFmpegConfig represents FFmpeg configuration +type FFmpegConfig struct { + FFmpegPath string `json:"ffmpeg_path" yaml:"ffmpeg_path"` // Required, path to ffmpeg + FFprobePath string `json:"ffprobe_path" yaml:"ffprobe_path"` // Required, path to ffprobe + EnableGPU bool `json:"enable_gpu,omitempty" yaml:"enable_gpu"` // Optional, default false + GPUIndex int `json:"gpu_index,omitempty" yaml:"gpu_index"` // GPU index (-1 means auto detect) + MaxProcesses int `json:"max_processes,omitempty" yaml:"max_processes"` // Optional, -1 means max cpu cores + MaxThreads int `json:"max_threads,omitempty" yaml:"max_threads"` // Optional, -1 means max cpu threads +} + +// LimitsConfig represents concurrency limits configuration +type LimitsConfig struct { + Job *QueueLimit `json:"job,omitempty" yaml:"job"` // Job queue limits + Chunking *QueueLimit `json:"chunking,omitempty" yaml:"chunking"` // Chunking limits + Embedding *QueueLimit `json:"embedding,omitempty" yaml:"embedding"` // Embedding limits + Converter *QueueLimit `json:"converter,omitempty" yaml:"converter"` // Converter limits + Extractor *QueueLimit `json:"extractor,omitempty" yaml:"extractor"` // Extractor limits + Fetcher *QueueLimit `json:"fetcher,omitempty" yaml:"fetcher"` // Fetcher limits + Searcher *QueueLimit `json:"searcher,omitempty" yaml:"searcher"` // Searcher limits + Reranker *QueueLimit `json:"reranker,omitempty" yaml:"reranker"` // Reranker limits + Vote *QueueLimit `json:"vote,omitempty" yaml:"vote"` // Vote limits + Weight *QueueLimit `json:"weight,omitempty" yaml:"weight"` // Weight limits + Score *QueueLimit `json:"score,omitempty" yaml:"score"` // Score limits +} + +// QueueLimit represents queue and concurrency limits +type QueueLimit struct { + MaxConcurrent int `json:"max_concurrent,omitempty" yaml:"max_concurrent"` // Maximum concurrent operations + QueueSize int `json:"queue_size,omitempty" yaml:"queue_size"` // Queue size (0 means unlimited) +} + +// Provider represents a service provider configuration (chunking, embedding, converter, extractor, fetcher, searcher, etc.) +type Provider struct { + ID string `json:"id" yaml:"id"` // Required, unique id for the provider + Label string `json:"label" yaml:"label"` // Required, label for the provider, for display + Description string `json:"description" yaml:"description"` // Required, description for the provider, for display + Default bool `json:"default,omitempty" yaml:"default"` // Optional, default is false, if true, will be used as the default provider + Options []*ProviderOption `json:"options" yaml:"options"` // Available preset provider options +} + +// ProviderOption represents an option for a provider +type ProviderOption struct { + Label string `json:"label" yaml:"label"` // Required, label for the option, for display + Value string `json:"value" yaml:"value"` // Required, unique value for the option + Description string `json:"description" yaml:"description"` // Required, description for the option, for display + Default bool `json:"default,omitempty" yaml:"default"` // Optional, default is false, if true, will be used as the default option + Properties map[string]interface{} `json:"properties" yaml:"properties"` // Required, properties for the option +} + +// ProviderSchema defines the unified schema for a provider's properties (data + UI in one) +type ProviderSchema struct { + ID string `json:"id" yaml:"id"` // Provider ID this schema applies to + Title string `json:"title,omitempty" yaml:"title"` // Optional title for the schema + Description string `json:"description,omitempty" yaml:"description"` // Optional description + Properties map[string]*PropertySchema `json:"properties" yaml:"properties"` // Property definitions + Required []string `json:"required,omitempty" yaml:"required"` // Required property names +} + +// PropertySchema defines both data structure and UI configuration for a single property +type PropertySchema struct { + // Data Structure (similar to JSON Schema) + Type PropertyType `json:"type" yaml:"type"` // Property type + Title string `json:"title,omitempty" yaml:"title"` // Display title + Description string `json:"description,omitempty" yaml:"description"` // Property description + Default interface{} `json:"default,omitempty" yaml:"default"` // Default value + Enum []EnumOption `json:"enum,omitempty" yaml:"enum"` // Enumeration options (with labels) + + // Validation Constraints + Required bool `json:"required,omitempty" yaml:"required"` // Is this property required + MinLength *int `json:"minLength,omitempty" yaml:"minLength"` // String min length + MaxLength *int `json:"maxLength,omitempty" yaml:"maxLength"` // String max length + Pattern *string `json:"pattern,omitempty" yaml:"pattern"` // Regex pattern + Minimum *float64 `json:"minimum,omitempty" yaml:"minimum"` // Number minimum + Maximum *float64 `json:"maximum,omitempty" yaml:"maximum"` // Number maximum + + // UI Configuration + Component string `json:"component,omitempty" yaml:"component"` // UI component type (Input, Select, Textarea, etc.) + Placeholder string `json:"placeholder,omitempty" yaml:"placeholder"` // Input placeholder + Help string `json:"help,omitempty" yaml:"help"` // Help text + Order int `json:"order,omitempty" yaml:"order"` // Display order + Hidden bool `json:"hidden,omitempty" yaml:"hidden"` // Hide field + Disabled bool `json:"disabled,omitempty" yaml:"disabled"` // Disable field + ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly"` // Read-only field + Width string `json:"width,omitempty" yaml:"width"` // Field width (full, half, quarter) + Group string `json:"group,omitempty" yaml:"group"` // Group name for organizing fields + + // Nested Properties (for object types) + Properties map[string]*PropertySchema `json:"properties,omitempty" yaml:"properties"` // Object properties + + // Array Items (for array types) + Items *PropertySchema `json:"items,omitempty" yaml:"items"` // Array items schema +} + +// PropertyType represents the type of a property +type PropertyType string + +// Property type constants +const ( + PropertyTypeString PropertyType = "string" // PropertyTypeString represents a string property + PropertyTypeNumber PropertyType = "number" // PropertyTypeNumber represents a number property + PropertyTypeInteger PropertyType = "integer" // PropertyTypeInteger represents an integer property + PropertyTypeBoolean PropertyType = "boolean" // PropertyTypeBoolean represents a boolean property + PropertyTypeObject PropertyType = "object" // PropertyTypeObject represents an object property + PropertyTypeArray PropertyType = "array" // PropertyTypeArray represents an array property +) + +// EnumOption represents an enumeration option with both value and display label +type EnumOption struct { + Value string `json:"value" yaml:"value"` // Actual value + Label string `json:"label" yaml:"label"` // Display label + Desc string `json:"desc,omitempty" yaml:"desc"` // Optional description + Icon string `json:"icon,omitempty" yaml:"icon"` // Optional icon +} + +// RawConfig is an alias for Config to enable custom JSON marshaling/unmarshaling +type RawConfig Config diff --git a/yao/stores/kb/cache.lru.yao b/yao/stores/kb/cache.lru.yao new file mode 100644 index 00000000..4351660e --- /dev/null +++ b/yao/stores/kb/cache.lru.yao @@ -0,0 +1,13 @@ +{ + "label": "Knowledge Base Cache Store", + "description": "LRU cache store for Knowledge Base temporary data", + "tags": ["kb", "cache", "lru", "token"], + "readonly": false, + "builtin": true, + "sort": 11, + "name": "Knowledge Base Cache Store", + "type": "lru", + "option": { + "size": 8192 + } +} diff --git a/yao/stores/kb/store.badger.yao b/yao/stores/kb/store.badger.yao new file mode 100644 index 00000000..e44a96c1 --- /dev/null +++ b/yao/stores/kb/store.badger.yao @@ -0,0 +1,13 @@ +{ + "label": "Knowledge Base Data Store", + "description": "Badger-based persistent store for Knowledge Base data", + "tags": ["kb", "persistent", "badger", "data"], + "readonly": false, + "builtin": true, + "sort": 10, + "name": "Knowledge Base Data Store", + "type": "badger", + "option": { + "path": "{{ YAO_DATA_ROOT }}/stores/kb/store" + } +}