examples

package
v0.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2026 License: None detected not legal advice Imports: 0 Imported by: 0

Documentation

Overview

Package examples provides runnable examples for flyto-agent.

All examples in this package use the Go Example function convention (ExampleXxx) so they are indexed by pkgsite/godoc automatically.

Examples that require a real API key are guarded by os.Getenv checks and will produce no output when run without credentials.

Run a specific example:

go test -v -run Example_basic ./examples/
Example (Basic)

Example_basic demonstrates starting an agent in minimal form.

package main

import (
	"context"
	"fmt"
	"os"

	"git.flytoex.net/yuanwei/flyto-agent/pkg/engine"
	"git.flytoex.net/yuanwei/flyto-agent/pkg/execenv"
	"git.flytoex.net/yuanwei/flyto-agent/pkg/providers/anthropic"
)

func main() {
	agent, err := engine.New(&engine.Config{
		Model: "claude-sonnet-4-6",
		Provider: anthropic.New(anthropic.Config{
			APIKey: os.Getenv("ANTHROPIC_API_KEY"),
		}),
		Cwd:      ".",
		Executor: execenv.DefaultExecutor{},
		Tools:    []string{"Bash", "Read", "Edit", "Glob", "Grep"},
	})
	if err != nil {
		fmt.Fprintln(os.Stderr, "error:", err)
		return
	}
	defer agent.Close()

	for event := range agent.Run(context.Background(), "查看当前目录结构") {
		switch e := event.(type) {
		case *engine.TextDeltaEvent:
			fmt.Print(e.Text)
		case *engine.ToolUseEvent:
			fmt.Printf("\n🔧 %s\n", e.ToolName)
		case *engine.DoneEvent:
			fmt.Printf("\n--- done: %d turns $%.4f ---\n", e.TurnCount, e.TotalCostUSD)
		case *engine.ErrorEvent:
			fmt.Fprintln(os.Stderr, "error:", e.Err)
		}
	}
}
Example (Debate)

Example_debate demonstrates Agent Teams peer-to-peer messaging primitives without calling a real LLM.

Two workers (proposer/critic) exchange messages through inbox.Router, simulating a proposal debate. Replace agent names and content strings to adapt to finance / medical / logistics / legal scenarios.

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"git.flytoex.net/yuanwei/flyto-agent/pkg/inbox"
)

func main() {
	ctx := context.Background()
	router := inbox.NewRouter()
	defer router.Close()

	const (
		proposer = "proposer"
		critic   = "critic"
		leader   = "leader"
	)

	mustSend(router, proposer, critic, "建议采用方案 A: Redis 做 task list. 低延迟, 成熟.")

	msg := mustRecvFrom(ctx, router, critic)
	fmt.Printf("[critic from=%s] %s\n", msg.From, payloadContent(msg))
	mustSend(router, critic, proposer, "反对. Redis 非持久化, SaaS 需要审计表. 方案 B: PostgreSQL.")

	msg = mustRecvFrom(ctx, router, proposer)
	fmt.Printf("[proposer from=%s] %s\n", msg.From, payloadContent(msg))
	mustSend(router, proposer, critic, "折中: Postgres 主存 + Redis 缓存, CDC 同步.")

	msg = mustRecvFrom(ctx, router, critic)
	fmt.Printf("[critic from=%s] %s\n", msg.From, payloadContent(msg))
	mustSend(router, critic, leader, "达成折中方案, 请裁决.")

	msg = mustRecvFrom(ctx, router, leader)
	fmt.Printf("[leader from=%s] %s\n", msg.From, payloadContent(msg))
}

func mustSend(router *inbox.Router, from, to, content string) {
	msg, err := inbox.NewMessage(from, to, inbox.MsgTaskAssignment, map[string]string{"content": content})
	if err != nil {
		log.Fatal(err)
	}
	if err := router.Send(to, msg); err != nil {
		log.Fatal(err)
	}
}

func payloadContent(msg *inbox.Message) string {
	var p map[string]string
	if err := json.Unmarshal(msg.Payload, &p); err != nil {
		return string(msg.Payload)
	}
	return p["content"]
}

func mustRecvFrom(ctx context.Context, router *inbox.Router, to string) *inbox.Message {
	msg, err := router.Inbox(to).Recv(ctx)
	if err != nil {
		log.Fatalf("recv %s: %v", to, err)
	}
	return msg
}
Example (TasklistCustom)

Example_tasklistCustom demonstrates plugging in a custom Store backend (finance compliance audit scenario).

Implement tasklist.Store (Get / CAS / List / Close) to connect any storage: PostgreSQL, HIPAA-encrypted store, WMS wave records, etc.

package main

import (
	"context"
	"fmt"
	"sort"
	"sync"

	"git.flytoex.net/yuanwei/flyto-agent/pkg/tasklist"
)

func main() {
	ctx := context.Background()
	store := newFinanceAuditStore()
	tl := tasklist.New(store)
	defer tl.Close()

	trade, err := tl.Add(ctx, "审核: 买入 AAPL 10000 股", "价格 $180, 客户 XYZ-001")
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	if _, err := tl.Claim(ctx, trade.ID, "risk-analyst-03"); err != nil {
		fmt.Println("error:", err)
		return
	}
	done, err := tl.Complete(ctx, trade.ID, "批准: VaR=2.1% 在阈值内")
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Printf("completed: %s\n", done.Result)

	for i, e := range store.auditLog() {
		fmt.Printf("%d. op=%s\n", i+1, e.operation)
	}
}

type auditEntry struct {
	operation string
	taskID    string
}

type financeAuditStore struct {
	mu   sync.Mutex
	data map[string]tasklist.Task
	log  []auditEntry
}

func newFinanceAuditStore() *financeAuditStore {
	return &financeAuditStore{data: make(map[string]tasklist.Task)}
}

func (s *financeAuditStore) Get(_ context.Context, id string) (tasklist.Task, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	t, ok := s.data[id]
	if !ok {
		return tasklist.Task{}, tasklist.ErrTaskNotFound
	}
	return t, nil
}

func (s *financeAuditStore) CAS(_ context.Context, id string, expectedVersion int, newTask tasklist.Task) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	current, exists := s.data[id]
	if expectedVersion == 0 {
		if exists {
			return tasklist.ErrTaskAlreadyExists
		}
		s.data[id] = newTask
		s.log = append(s.log, auditEntry{"CREATE", id})
		return nil
	}
	if !exists {
		return tasklist.ErrTaskNotFound
	}
	if current.Version != expectedVersion {
		return tasklist.ErrConcurrentModification
	}
	s.data[id] = newTask
	op := "UPDATE"
	switch newTask.Status {
	case tasklist.StatusClaimed:
		op = "CLAIM"
	case tasklist.StatusCompleted:
		op = "COMPLETE"
	case tasklist.StatusFailed:
		op = "FAIL"
	}
	s.log = append(s.log, auditEntry{op, id})
	return nil
}

func (s *financeAuditStore) List(_ context.Context) ([]tasklist.Task, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	out := make([]tasklist.Task, 0, len(s.data))
	for _, t := range s.data {
		out = append(out, t)
	}
	sort.Slice(out, func(i, j int) bool { return out[i].CreatedAt.Before(out[j].CreatedAt) })
	return out, nil
}

func (s *financeAuditStore) Close() error { return nil }

func (s *financeAuditStore) auditLog() []auditEntry { return s.log }
Example (TasklistMarkdown)

Example_tasklistMarkdown demonstrates MarkdownStore cross-tool interop.

The tasks.md file format is compatible with Claude Code v2.1.32: files written by Flyto can be read by Claude Code and vice versa.

package main

import (
	"context"
	"fmt"
	"os"

	"git.flytoex.net/yuanwei/flyto-agent/pkg/tasklist"
)

func main() {
	ctx := context.Background()
	path := "/tmp/flyto_example_tasks.md"
	defer os.Remove(path)

	tl := tasklist.New(tasklist.NewMarkdownStore(path))
	defer tl.Close()

	var ids []string
	for _, s := range []string{"分析日志找错误模式", "编写 login 模块单元测试"} {
		t, err := tl.Add(ctx, s, "")
		if err != nil {
			fmt.Println("error:", err)
			return
		}
		ids = append(ids, t.ID)
		fmt.Printf("[add] %s\n", t.Subject)
	}

	if _, err := tl.Claim(ctx, ids[0], "worker-A"); err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println("[worker-A claimed]")

	done, err := tl.Complete(ctx, ids[1], "8 edge cases covered")
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Printf("[worker-B completed] %s\n", done.Subject)
}
Example (WithPricing)

Example_withPricing demonstrates full integration: provider / pricing / tools / cost tracking.

package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"git.flytoex.net/yuanwei/flyto-agent/pkg/config"
	"git.flytoex.net/yuanwei/flyto-agent/pkg/engine"
	"git.flytoex.net/yuanwei/flyto-agent/pkg/execenv"
	"git.flytoex.net/yuanwei/flyto-agent/pkg/pricing"
	"git.flytoex.net/yuanwei/flyto-agent/pkg/providers/anthropic"
)

func main() {
	registry := config.NewModelRegistry()
	if n, err := pricing.LoadAndRegister(registry); err != nil {
		fmt.Fprintf(os.Stderr, "warning: pricing unavailable: %v\n", err)
	} else {
		fmt.Fprintf(os.Stderr, "loaded pricing for %d models\n", n)
	}

	agent, err := engine.New(&engine.Config{
		Provider: anthropic.New(anthropic.Config{
			APIKey:        os.Getenv("ANTHROPIC_API_KEY"),
			BaseURL:       os.Getenv("ANTHROPIC_BASE_URL"),
			EnableCaching: true,
		}),
		Model:        "claude-sonnet-4-6",
		Cwd:          ".",
		Executor:     execenv.DefaultExecutor{},
		Tools:        []string{"Bash", "Read", "Glob", "Grep"},
		Models:       registry,
		MaxTurns:     20,
		MaxBudgetUSD: 0.50,
		SystemPrompt: "你是一个简洁的代码探索助手,回答精准。",
	})
	if err != nil {
		fmt.Fprintln(os.Stderr, "fatal:", err)
		return
	}
	defer agent.Close()

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

	var toolCalls int
	start := time.Now()
	for event := range agent.Run(ctx, "用 Glob 找出当前目录下所有 .go 文件,告诉我数量") {
		switch e := event.(type) {
		case *engine.TextDeltaEvent:
			fmt.Print(e.Text)
		case *engine.ToolUseEvent:
			fmt.Printf("\n🔧 %s\n", e.ToolName)
			toolCalls++
		case *engine.WarningEvent:
			fmt.Fprintf(os.Stderr, "⚠️  [%s] %s\n", e.Code, e.Message)
		case *engine.ErrorEvent:
			fmt.Fprintln(os.Stderr, "error:", e.Err)
		case *engine.DoneEvent:
			fmt.Printf("\n--- done: %d turns %v $%.4f %d tool calls ---\n",
				e.TurnCount, time.Since(start).Round(time.Millisecond), e.TotalCostUSD, toolCalls)
		}
	}
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL