Files
Enterprise-Knowledge-Base/cli/cmd/kb/create.go
T
nullkey 1b20b06f5e feat(cli): --json field-select, --jq, auth token, doc --from-url
Output ergonomics:
- `--json` accepts a comma-separated field list (gh-parity); selects
  named keys from the per-command payload. Bare `--json` keeps the
  full shape.
- `--jq <expr>` evaluates a gojq expression over the JSON; pairs with
  `--json field-list` so projection runs before jq.
- `--version` is a global cobra flag in addition to the `version`
  subcommand; both render the same line.
- Per-command `--help` now renders the available JSON field list under
  "JSON fields available via `--json id,name,...`" (field-discovery
  parity with gh / kubectl `-o jsonpath`).

New commands:
- `auth token` — print the active context's credential to stdout for
  shell command substitution (`WEKNORA_TOKEN=$(weknora auth token)`).
  Default: raw secret, no trailing newline. `--json` emits
  `{token, mode, context}`.
- `doc upload --from-url <URL>` — ingest a remote URL via the SDK
  `CreateKnowledgeFromURL`. `--name` forwarded as `FileName` so the
  server's known-extension heuristic upgrades crawl-mode to
  file-download-mode where appropriate.

Includes the simplify post-review polish pass (field-filter unit
tests, --json/--jq compose check, agent_help copy fixes).
2026-05-15 12:03:56 +08:00

106 lines
3.6 KiB
Go

package kb
import (
"context"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/Tencent/WeKnora/cli/internal/agent"
"github.com/Tencent/WeKnora/cli/internal/cmdutil"
"github.com/Tencent/WeKnora/cli/internal/format"
"github.com/Tencent/WeKnora/cli/internal/iostreams"
sdk "github.com/Tencent/WeKnora/client"
)
// kbCreateFields enumerates the fields surfaced for `--json` discovery on
// `kb create`. The result is the full KnowledgeBase struct; these mirror its
// top-level json tags. Nested config objects are intentionally omitted —
// users wanting them can drop --json (no filter) or use --jq.
var kbCreateFields = []string{
"id", "name", "type", "description",
"is_temporary", "is_pinned",
"embedding_model_id", "summary_model_id",
"knowledge_count", "chunk_count",
"is_processing", "processing_count",
"created_at", "updated_at",
}
type CreateOptions struct {
Name string
Description string
EmbeddingModel string
DryRun bool
}
// CreateService is the narrow SDK surface this command depends on.
// *sdk.Client satisfies it via duck typing (ADR-4).
type CreateService interface {
CreateKnowledgeBase(ctx context.Context, kb *sdk.KnowledgeBase) (*sdk.KnowledgeBase, error)
}
// NewCmdCreate builds `weknora kb create`.
func NewCmdCreate(f *cmdutil.Factory) *cobra.Command {
opts := &CreateOptions{}
cmd := &cobra.Command{
Use: "create --name <name>",
Short: "Create a new knowledge base",
Args: cobra.NoArgs,
RunE: func(c *cobra.Command, _ []string) error {
jopts, err := cmdutil.CheckJSONFlags(c)
if err != nil {
return err
}
opts.DryRun = cmdutil.IsDryRun(c)
if opts.DryRun {
return runCreate(c.Context(), opts, jopts, nil) // service unused on dry-run
}
cli, err := f.Client()
if err != nil {
return err
}
return runCreate(c.Context(), opts, jopts, cli)
},
}
cmd.Flags().StringVar(&opts.Name, "name", "", "Knowledge base name (required)")
cmd.Flags().StringVar(&opts.Description, "description", "", "Knowledge base description (optional)")
cmd.Flags().StringVar(&opts.EmbeddingModel, "embedding-model", "", "Embedding model ID (optional; server picks default when unset)")
cmdutil.AddJSONFlags(cmd, kbCreateFields)
agent.SetAgentHelp(cmd, "Creates a knowledge base under the active context. --name is required; --description and --embedding-model are optional. Returns data: full KnowledgeBase object including the new id.")
return cmd
}
func runCreate(ctx context.Context, opts *CreateOptions, jopts *cmdutil.JSONOptions, svc CreateService) error {
// Validate locally before any HTTP — keeps `input.invalid_argument`
// distinct from a server-side 400.
if strings.TrimSpace(opts.Name) == "" {
return cmdutil.NewError(cmdutil.CodeInputInvalidArgument, "--name is required")
}
req := &sdk.KnowledgeBase{
Name: opts.Name,
Description: opts.Description,
}
if opts.EmbeddingModel != "" {
req.EmbeddingModelID = opts.EmbeddingModel
}
if opts.DryRun {
return cmdutil.EmitDryRun(jopts.Enabled(), req, nil,
&format.Risk{Level: format.RiskWrite, Action: fmt.Sprintf("create knowledge base %q", opts.Name)})
}
created, err := svc.CreateKnowledgeBase(ctx, req)
if err != nil {
return cmdutil.WrapHTTP(err, "create knowledge base")
}
if jopts.Enabled() {
risk := &format.Risk{Level: format.RiskWrite, Action: fmt.Sprintf("created knowledge base %s", created.ID)}
return format.WriteEnvelopeFiltered(iostreams.IO.Out, format.SuccessWithRisk(created, &format.Meta{KBID: created.ID}, risk), jopts.Fields, jopts.JQ)
}
fmt.Fprintf(iostreams.IO.Out, "✓ Created knowledge base %q (id: %s)\n", created.Name, created.ID)
return nil
}