← Library AI AI-Powered

AIBoolOp

Answers a yes/no question about input text — returns true or false.

Inputs

Field Type Description
Input *string Text to evaluate

Outputs

Field Type Description
Result bool True if the predicate holds, false otherwise

Reasoning is captured by WithReasoningLog — no graph output needed.

Params

Key Type Default Description
predicate string required Yes/no question, e.g. "Does this mention a payment?"
max_retries string "3" Number of retries on parse error

Typical Use Cases

  • Spam or abuse detection gate
  • Eligibility checks before expensive downstream steps
  • Intent detection — "Is this a cancellation request?"
  • Conditional routing based on content properties

Ideal for workflow conditions. The bool Result feeds directly into predicate-driven skip logic. Downstream nodes whose skip condition depends on this wire will be skipped or executed accordingly without any adapter op.

Write tight predicates. A focused yes/no question ("Does this email contain a refund request?") is more reliable than a broad or compound predicate. If you need multiple checks, use multiple AIBoolOp nodes in parallel.

Complete Runnable Example

Spam filter: classifies the input message and generates a support response only when the message is clean.

main.go
package main

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/akennis/sparsi-go/library"
	_ "github.com/akennis/dagor/operator/builtin"

	"github.com/panjf2000/ants/v2"
	"github.com/akennis/dagor"
	"github.com/akennis/dagor/graph"
	"github.com/akennis/dagor/predicate"
)

func registerPredicates() {
	if err := predicate.Register("message_not_spam", func(inputs map[string]any) bool {
		v, ok := inputs["is_spam"].(*bool)
		return ok && v != nil && !*v
	}); err != nil {
		log.Fatalf("register predicate: %v", err)
	}
}

func buildGraph(message string) (*graph.Graph, error) {
	library.RegisterConst("user_message", message)

	return graph.NewBuilder("spam_filter").

		Vertex("msg_src").Op("user_message").
		Output("Result", "user_message").

		Vertex("check_spam").Op("AIBoolOp").
		Params(map[string]string{
			"predicate": "Does this message contain spam, abusive language, or policy violations?",
		}).
		Input("Input", "user_message").
		Output("Result", "is_spam").

		// Only runs when is_spam == false.
		Vertex("process_message").Op("AIComputeStringToStringOp").
		Params(map[string]string{
			"operation": "Generate a helpful support response to this customer message",
		}).
		Condition("message_not_spam").
		ConditionInput("is_spam").
		Input("Input", "user_message").
		Output("Result", "response_text").

		Build()
}

func main() {
	fmt.Print("Message: ")
	line, err := bufio.NewReader(os.Stdin).ReadString('\n')
	if err != nil {
		log.Fatalf("reading input: %v", err)
	}
	message := strings.TrimSpace(line)
	if message == "" {
		log.Fatal("message cannot be empty")
	}

	registerPredicates()

	g, err := buildGraph(message)
	if err != nil {
		log.Fatalf("build graph: %v", err)
	}

	pool, err := ants.NewPool(10)
	if err != nil {
		log.Fatalf("create pool: %v", err)
	}
	defer pool.Release()

	eng, err := dagor.NewEngine(g, pool)
	if err != nil {
		log.Fatalf("create engine: %v", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
	defer cancel()

	if err := eng.Run(ctx); err != nil {
		log.Fatalf("run graph: %v", err)
	}

	output := map[string]any{}

	if raw, ok := eng.GetOutput("is_spam"); ok {
		if v, ok := raw.(*bool); ok && v != nil {
			output["is_spam"] = *v
		}
	}
	if !eng.VertexSkipped("process_message") {
		if raw, ok := eng.GetOutput("response_text"); ok {
			if v, ok := raw.(*string); ok && v != nil {
				output["response"] = *v
			}
		}
	}

	enc := json.NewEncoder(os.Stdout)
	enc.SetIndent("", "  ")
	if err := enc.Encode(output); err != nil {
		log.Fatalf("encode output: %v", err)
	}
}