mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-09-19 02:18:25 +08:00
Three defects surfaced during end-to-end RAG verification — the first two
block real chat usage, the third makes Linux CI flaky:
1. KB id detection — `IsKBID` was checking
`strings.HasPrefix(s, "kb_")`, but WeKnora generates KB ids as bare
UUIDs (internal/types/knowledge_base.go: `uuid.New().String()` stored
in a `varchar(36)` column). Real ids therefore fell through to the
name-resolution path:
$ weknora chat ... --kb a32a63ff-fb36-4874-bcaa-30f48570a694
Error: knowledge base not found: a32a63ff-...
Switched the discriminator to a UUID regex
(`^[0-9a-fA-F]{8}-…-[0-9a-fA-F]{12}$`). KB names are arbitrary
user-supplied strings, so the canonical 8-4-4-4-12 form is an
unambiguous signal. Mirrors gcloud `--project`'s id-vs-name detection.
2. SSE terminal-frame — the accumulator's `Append` was gating
finalization on `r.Done`, but the server's KnowledgeQAStream protocol
emits a leading `agent_query` frame with `done=true` to deliver
session + message metadata *before* the answer fragments arrive:
event: message
data: {"response_type":"agent_query","content":"","done":true,…}
event: message
data: {"response_type":"answer","content":"你好","done":false}
…
event: message
data: {"response_type":"complete","content":"","done":true}
The accumulator therefore flipped to `finished=true` on frame #1 and
discarded every subsequent answer fragment — `weknora chat … --json`
returned `answer: ""` even though the LLM reported completion_tokens
> 0. Fixed: terminate only on `response_type == complete`.
References still captured opportunistically (they may arrive on a
dedicated `references` event before the terminator).
3. doctor credential_storage CI isolation — the check probes the real
OS keyring via `secrets.NewBestEffortStore()`: present on macOS dev
machines → StatusOK; absent on Linux CI runners without libsecret /
Gnome-Keyring → StatusWarn ("falling back to file store"). That
host-dependence was leaking into two test classes that assumed
StatusOK:
* cmd/doctor/doctor_test.go: TestDoctor_AllOK and
TestDoctor_NoConfig_StillRunsCredentialStorage already had a
withCredStoreFactory seam but didn't use it. Added the pin.
* acceptance/contract/envelope_test.go: doctor.success_offline
and doctor.error_network golden cases. The contract test runs
through the cobra tree in-process and shares cmd/doctor's
package-level credStoreFactory var — but couldn't reach it
because the existing seam was unexported.
Fix: export `doctor.SetCredStoreFactoryForTest(fn) (restore func())`
for out-of-package tests; acceptance/contract/helpers_test.go adds
a TestMain that pins the factory to a MemStore-returning closure
for the whole suite (MemStore is neither *FileStore nor a real
keyring, so doctor's type-switch hits StatusOK). Production stays
at secrets.NewBestEffortStore — only the test hook is now reachable
from across packages.
Test fixtures and goldens that used the old `kb_xxx` literals or
`Done: true` terminators were rewritten to use real UUIDs and
`ResponseType: ResponseTypeComplete` respectively. Per-command --help
text and Long descriptions / Examples now show a UUID rather than
`kb_…` so users see the correct shape from the start. New
TestAccumulator_IgnoresAgentQueryDone pins the SSE terminator bug so
it can't regress.
Tests: 24 cli packages green on macOS dev + Linux/macOS/Windows CI
matrix. Verified end-to-end against a live WeKnora server: `weknora
chat "..." --kb <UUID> --no-stream --json` returns the full LLM answer
in the envelope, live token streaming in TTY mode works, and the
credential_storage check renders deterministic envelopes across hosts.
185 lines
5.1 KiB
Markdown
185 lines
5.1 KiB
Markdown
# weknora — WeKnora CLI
|
||
|
||
A command-line interface for the WeKnora RAG knowledge-base server. Lets you
|
||
authenticate, manage knowledge bases and documents, run hybrid search, and
|
||
ask streaming RAG questions from your terminal or from an AI agent.
|
||
|
||
```bash
|
||
$ weknora --help
|
||
WeKnora CLI lets you authenticate, browse knowledge bases, and run
|
||
hybrid searches against a WeKnora server from your shell or an AI agent.
|
||
|
||
Available Commands:
|
||
api Make a raw API request to the WeKnora server
|
||
auth Manage authentication credentials and contexts
|
||
chat Ask a streaming RAG question against a knowledge base
|
||
context Manage CLI contexts (named connection targets)
|
||
doc Manage documents in a knowledge base
|
||
doctor Run 4 self-checks: base URL, auth, server version, credential storage
|
||
kb Manage knowledge bases
|
||
link Bind the current directory to a knowledge base
|
||
search Hybrid (vector + keyword) chunk retrieval against a knowledge base
|
||
version Show CLI build metadata
|
||
```
|
||
|
||
The command surface mirrors `gh` CLI's `<noun> <verb>` convention. See
|
||
[AGENTS.md](AGENTS.md) for the operational contract that AI agents
|
||
(Claude Code, Cursor, Aider, …) can rely on: envelope schema, exit-code
|
||
protocol, error-code registry, and per-command guidance.
|
||
|
||
---
|
||
|
||
## Install
|
||
|
||
### From source
|
||
|
||
Requires Go 1.24+.
|
||
|
||
```bash
|
||
git clone https://github.com/Tencent/WeKnora.git
|
||
cd WeKnora/cli
|
||
go build -o weknora .
|
||
sudo mv weknora /usr/local/bin/ # or anywhere on $PATH
|
||
```
|
||
|
||
### Pre-built binaries
|
||
|
||
Pre-built binaries for Linux / macOS / Windows are produced by CI on each
|
||
release. Grab the latest from the [Releases page](https://github.com/Tencent/WeKnora/releases)
|
||
once v0.2 ships.
|
||
|
||
---
|
||
|
||
## 5-minute quickstart
|
||
|
||
```bash
|
||
# 1. Log in to your WeKnora server (interactive password prompt)
|
||
weknora auth login --host https://kb.example.com
|
||
|
||
# 2. Or pipe an API key from stdin (for CI / agents)
|
||
echo "sk-..." | weknora auth login --host https://kb.example.com --with-token
|
||
|
||
# 3. List knowledge bases
|
||
weknora kb list
|
||
|
||
# 4. Bind this directory to a knowledge base — subsequent commands auto-resolve --kb
|
||
weknora link --kb my-knowledge-base
|
||
|
||
# 5. Upload a document
|
||
weknora doc upload notes.md
|
||
|
||
# 6. Search
|
||
weknora search "what is reciprocal rank fusion?"
|
||
|
||
# 7. Ask the LLM (streams to terminal)
|
||
weknora chat "summarise the design doc"
|
||
```
|
||
|
||
---
|
||
|
||
## Multi-context
|
||
|
||
Switch between several WeKnora servers (or several tenants on the same server)
|
||
without re-logging in:
|
||
|
||
```bash
|
||
weknora auth login --host https://prod.example.com --name prod
|
||
weknora auth login --host https://staging.example.com --name staging --with-token < .staging-key
|
||
weknora auth list
|
||
weknora context use prod
|
||
```
|
||
|
||
Credentials are persisted to your OS keyring (Keychain on macOS, libsecret on
|
||
Linux, Wincred on Windows) when available, otherwise to a 0600-mode file
|
||
under `$XDG_CONFIG_HOME/weknora/secrets/`. The active context lives in
|
||
`~/.config/weknora/config.yaml`.
|
||
|
||
To remove a context's stored credentials:
|
||
|
||
```bash
|
||
weknora auth logout # current context
|
||
weknora auth logout --name staging # specific
|
||
weknora auth logout --all
|
||
```
|
||
|
||
---
|
||
|
||
## JSON envelope output
|
||
|
||
Every command supports `--json`, returning a stable envelope shape:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"data": { /* command-specific payload */ },
|
||
"_meta": { "context": "prod", "kb_id": "a32a63ff-fb36-4874-bcaa-30f48570a694" }
|
||
}
|
||
```
|
||
|
||
On error:
|
||
|
||
```json
|
||
{
|
||
"ok": false,
|
||
"error": {
|
||
"code": "auth.unauthenticated",
|
||
"message": "...",
|
||
"hint": "run `weknora auth login`"
|
||
}
|
||
}
|
||
```
|
||
|
||
The full schema, error-code registry, and exit-code protocol (0 / 1 / 2 / 10
|
||
/ 130) are documented in [AGENTS.md](AGENTS.md).
|
||
|
||
---
|
||
|
||
## Agent / scripting integration
|
||
|
||
Designed to be agent-first:
|
||
|
||
- `--dry-run` previews any write command (kb create/delete, doc
|
||
upload/delete, api POST/PUT/PATCH/DELETE) without hitting the server,
|
||
emitting an envelope with `risk` classification and `dry_run: true`.
|
||
- `-y/--yes` skips confirmation prompts for high-risk writes. **Without
|
||
`-y` on a non-TTY/`--json` invocation, destructive commands return
|
||
`error.code: input.confirmation_required` and exit code 10** so an
|
||
agent can ask the user before retrying.
|
||
- `--json` coexists with the global `--context <name>` for single-shot
|
||
context override.
|
||
- Set `CLAUDECODE` or `CURSOR_AGENT` environment variables to surface
|
||
per-command "AI agents:" guidance in `--help` output.
|
||
|
||
---
|
||
|
||
## Health check
|
||
|
||
Run `weknora doctor` for a 4-status diagnostic (OK / warn / fail /
|
||
skip) covering base URL reachability, authentication, server-CLI
|
||
version skew, and credential storage backend. Add `--json` for
|
||
machine-readable output, `--offline` to skip network checks.
|
||
|
||
---
|
||
|
||
## Development
|
||
|
||
```bash
|
||
# Run unit + contract tests
|
||
go test ./...
|
||
|
||
# Run the real-server e2e suite (requires WEKNORA_E2E_HOST + token env vars)
|
||
go test -tags acceptance_e2e ./acceptance/e2e/...
|
||
|
||
# Static analysis
|
||
go vet ./...
|
||
```
|
||
|
||
CI (`.github/workflows/cli.yml`) runs build + unit + contract tests on Linux /
|
||
macOS / Windows × Go 1.24, path-filtered to changes under `cli/`.
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
MIT — see the repository [LICENSE](../LICENSE).
|