package main import ( "fmt" "os" "os/signal" "syscall" "github.com/langgenius/dify/dify-agent-runtime/internal/agentcli" "github.com/spf13/cobra" ) func newKnowledgeCommand() *cobra.Command { var protocolVersion bool root := &cobra.Command{Use: "knowledge", Short: "Autonomously inspect read-only KnowledgeFS evidence. All results are JSON.", RunE: func(cmd *cobra.Command, args []string) error { if protocolVersion { _, err := fmt.Fprintln(cmd.OutOrStdout(), "1") return err } return cmd.Help() }, Args: cobra.NoArgs} root.Flags().BoolVar(&protocolVersion, "protocol-version", false, "Print the locally supported knowledge protocol version.") definitions := []struct { name, description string flags []string }{ {"spaces", "List only spaces bound to this Agent and their current availability.", nil}, {"capabilities", "Inspect this space's current capabilities (no model credentials).", []string{"space"}}, {"search", "Retrieve evidence using the space profile; no nested planner or generated answer.", []string{"space", "query", "image-file-id", "limit"}}, {"ls", "List a bounded page of /knowledge entries.", []string{"space", "path", "cursor", "limit"}}, {"tree", "Browse a bounded /knowledge subtree.", []string{"space", "path", "cursor", "limit", "depth"}}, {"find", "Find /knowledge entries whose names contain the query.", []string{"space", "path", "query", "cursor", "limit"}}, {"grep", "Search text inside /knowledge with a bounded server timeout.", []string{"space", "path", "query", "cursor", "limit"}}, {"cat", "Read a page of text. Raw manifests and binary artifacts are not exposed.", []string{"space", "path", "cursor", "limit"}}, {"stat", "Inspect safe metadata for one /knowledge path.", []string{"space", "path"}}, {"diff", "Compare two readable paths without an LLM semantic-diff call.", []string{"space", "old-path", "new-path"}}, {"open", "Open a node ID or validate/reopen a trusted evidence receipt.", []string{"space", "node-id", "receipt"}}, {"images", "List image items and captions from a receipt's immutable document artifact.", []string{"space", "receipt", "cursor", "limit"}}, {"image", "Deliver one bounded image to a vision-capable Agent via the trusted runtime channel.", []string{"space", "receipt", "item-id"}}, } for _, definition := range definitions { cmd := &cobra.Command{Use: definition.name, Short: definition.description, Args: cobra.NoArgs} cmd.Flags().String("command-id", "", "Logical UUID for this command; generated by default. Reusing it will not repeat retrieval.") cmd.Flags().Bool("json", true, "Emit complete JSON (always enabled).") for _, flag := range definition.flags { switch flag { case "limit": cmd.Flags().Int(flag, 10, "Maximum returned items/segments (1–50); retrieval depth still belongs to the space profile.") case "depth": cmd.Flags().Int(flag, 2, "Maximum tree depth (1–4).") case "path": cmd.Flags().String(flag, "/knowledge", "Canonical read-only /knowledge path.") case "image-file-id": cmd.Flags().StringArray(flag, nil, "Authorized upload UUID or local_file dify-file-ref from inputs; repeat at most four times, never a URL.") default: cmd.Flags().String(flag, "", "Knowledge command "+flag+".") } } cmd.RunE = func(cmd *cobra.Command, args []string) error { env, err := agentcli.ReadEnvironment() if err != nil { return err } id, _ := cmd.Flags().GetString("command-id") if id == "" { id, err = agentcli.NewKnowledgeCommandID() if err != nil { return err } } payload := map[string]any{"version": 1, "command": cmd.Name(), "command_id": id} keys := map[string]string{"space": "space", "query": "query", "path": "path", "cursor": "cursor", "old-path": "old_path", "new-path": "new_path", "node-id": "node_id", "receipt": "receipt_id", "item-id": "item_id"} for flag, key := range keys { if cmd.Flags().Lookup(flag) != nil { value, _ := cmd.Flags().GetString(flag) if value != "" { payload[key] = value } } } for _, flag := range []string{"limit", "depth"} { if cmd.Flags().Lookup(flag) != nil { value, _ := cmd.Flags().GetInt(flag) payload[flag] = value } } if cmd.Flags().Lookup("image-file-id") != nil { images, _ := cmd.Flags().GetStringArray("image-file-id") if len(images) > 4 { return fmt.Errorf("knowledge search accepts at most four query images") } for index, value := range images { images[index], err = agentcli.KnowledgeQueryImageID(value) if err != nil { return err } } if len(images) > 0 { payload["image_file_ids"] = images } } ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, syscall.SIGTERM) defer stop() return agentcli.RunKnowledge(ctx, env, payload, cmd.OutOrStdout()) } root.AddCommand(cmd) } return root }