Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ One bot per platform. Agent selection is handled via the `/agent` command rather

Every channel supports `/new`, `/compact`, `/model`, `/agent`, `/whoami`, model switching, access control, and image input.

Lark workspace automation is no longer built in as `feishu_*` tools. If you want those workflows, install a `lark-cli` skill yourself and use it with `lark-cli` for calendar, docs, tasks, sheets, drive, and other workspace actions.

## Scheduler

You don't write cron expressions by hand. You just tell Anna what you need.
Expand Down
44 changes: 1 addition & 43 deletions cmd/anna/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (
"path/filepath"
"time"

lark "github.com/larksuite/oapi-sdk-go/v3"
larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
ucli "github.com/urfave/cli/v2"
"github.com/vaayne/anna/internal/agent"
"github.com/vaayne/anna/internal/agent/runner"
Expand All @@ -19,7 +17,6 @@ import (
"github.com/vaayne/anna/internal/channel"
"github.com/vaayne/anna/internal/config"
appdb "github.com/vaayne/anna/internal/db"
"github.com/vaayne/anna/internal/feishutool"
"github.com/vaayne/anna/internal/memory"
memorytool "github.com/vaayne/anna/internal/memory/tool"
pluginmgr "github.com/vaayne/anna/internal/plugin"
Expand Down Expand Up @@ -56,8 +53,7 @@ type setupResult struct {
extraTools []agenttool.Tool
notifier *channel.Dispatcher
pluginMgr *pluginmgr.Manager
fsClient *feishutool.Client // feishu client for OAuth (nil if not configured)
cliUserID int64 // resolved CLI user for session creation
cliUserID int64 // resolved CLI user for session creation
}

func setup(parent context.Context, gateway bool) (*setupResult, error) {
Expand Down Expand Up @@ -128,43 +124,6 @@ func setup(parent context.Context, gateway bool) (*setupResult, error) {
memorytool.NewMemoryTool(memoryEngine, userMemoryStore),
)

// Feishu tools: load config early (like scheduler/memory), create client
// and tools if configured, so all agents have access to Feishu APIs.
var fsClient *feishutool.Client
if fsCfg := loadChannelConfig[feishuChannelConfig](store, "feishu"); fsCfg != nil && fsCfg.AppID != "" && fsCfg.AppSecret != "" {
// Create token store for UAT token management.
tokenStore, tsErr := feishutool.NewSQLiteTokenStore(db, fsCfg.AppSecret)
if tsErr != nil {
slog.Warn("feishu token store creation failed, UAT disabled", "error", tsErr)
}

var clientOpts []feishutool.ClientOption
if tokenStore != nil {
clientOpts = append(clientOpts, feishutool.WithTokenStore(tokenStore))
}

larkClient := lark.NewClient(fsCfg.AppID, fsCfg.AppSecret,
lark.WithLogLevel(larkcore.LogLevelWarn),
lark.WithEnableTokenCache(true),
)
fsClient = feishutool.NewClient(larkClient, clientOpts...)
fsClient.SetAppCredentials(fsCfg.AppID, fsCfg.AppSecret)
sharedTools = append(sharedTools,
feishutool.NewUserTool(fsClient),
feishutool.NewCalendarTool(fsClient),
feishutool.NewTaskTool(fsClient),
feishutool.NewBitableTool(fsClient),
feishutool.NewChatTool(fsClient),
feishutool.NewIMTool(fsClient),
feishutool.NewDocTool(fsClient),
feishutool.NewWikiTool(fsClient),
feishutool.NewSheetsTool(fsClient),
feishutool.NewDriveTool(fsClient),
feishutool.NewSearchTool(fsClient),
)
slog.Info("feishu tools loaded", "uat_enabled", tokenStore != nil)
}

// Collect built-in tool names for plugin collision detection.
builtinReg := agenttool.NewRegistry("")
builtinNames := builtinReg.BuiltinNames()
Expand Down Expand Up @@ -254,7 +213,6 @@ func setup(parent context.Context, gateway bool) (*setupResult, error) {
extraTools: sharedTools,
notifier: dispatcher,
pluginMgr: pm,
fsClient: fsClient,
cliUserID: cliUserID,
}, nil
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/anna/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ func TestRunGatewayNoServices(t *testing.T) {
config.ResetAnnaHome()
t.Cleanup(config.ResetAnnaHome)
app := newApp()
err := app.Run([]string{"anna", "gateway"})
err := app.Run([]string{"anna", "--admin-port", "0", "gateway"})
if err == nil {
t.Fatal("expected error for no configured services")
}
if !strings.Contains(err.Error(), "no gateway services configured") {
t.Errorf("err = %q, want contains 'no gateway services configured'", err.Error())
if !strings.Contains(err.Error(), "no services to run") {
t.Errorf("err = %q, want contains 'no services to run'", err.Error())
}
}
11 changes: 1 addition & 10 deletions cmd/anna/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,23 +160,15 @@ func runServer(ctx context.Context, s *setupResult, listFn channel.ModelListFunc
if fsCfg != nil && fsCfg.AppID != "" && fsCfg.AppSecret != "" {
slog.Info("starting feishu bot")

fsOpts := []feishu.BotOption{
feishu.WithAuth(as, engine, linkCodes),
}
if s.fsClient != nil {
fsOpts = append(fsOpts, feishu.WithFeishuClient(s.fsClient))
}

fsBot, err := feishu.New(feishu.Config{
AppID: fsCfg.AppID,
AppSecret: fsCfg.AppSecret,
EncryptKey: fsCfg.EncryptKey,
VerificationToken: fsCfg.VerificationToken,
GroupMode: fsCfg.GroupMode,
Groups: fsCfg.Groups,
RedirectURI: fsCfg.RedirectURI,
}, s.poolManager, s.store, listFn, switchFn,
fsOpts...,
feishu.WithAuth(as, engine, linkCodes),
)
if err != nil {
return fmt.Errorf("create feishu bot: %w", err)
Expand Down Expand Up @@ -347,7 +339,6 @@ type feishuChannelConfig struct {
VerificationToken string `json:"verification_token"`
GroupMode string `json:"group_mode"`
Groups map[string]feishu.GroupConfig `json:"groups"`
RedirectURI string `json:"redirect_uri"`
EnableNotify bool `json:"enable_notify"`
}

Expand Down
Loading
Loading