connector/feishu is the optional Feishu/Lark surface: it receives Feishu
event callbacks, turns message events into agent runs, streams the replies
back as Feishu messages, hosts interactive question cards, and protects
against duplicate deliveries. It is the reference implementation of a
connector (see Extending) and depends only on
core plus the official
oapi-sdk-go/v3 SDK.
go get github.com/ishi-o/golem/connector/feishu
No environment variables are read — the app id, secret and webhook token come from your own configuration.
client, err := feishu.NewClient(feishu.ClientConfig{
AppID: appID, // required
AppSecret: appSecret, // required
BaseURL: "", // optional; Feishu default (Lark: the Lark domain)
Logger: logger,
})
The client wraps the official SDK, which owns tenant-token caching; the
small messaging surface (send text/cards by ReceiveIDType — open id,
user id, union id, email, chat id) is what the handler uses to reply.
handler := feishu.NewHandler(agent, backend, client, logger,
feishu.WithVerificationToken(token), // Feishu URL-verification + event tokens
feishu.WithQuestionTTL(24*time.Hour), // how long a question card stays answerable
)
NewHandler takes the agent, the store backend (duplicate-message
protection and pending questions are records in it), the client, a logger
and options. The handler is an http.Handler for the event webhook:
mux := http.NewServeMux()
mux.Handle("/webhooks/feishu", handler)
or mounted on your own HTTP service at any route of your choosing, e.g.
POST /webhooks/feishu.
FireOrQueue) and read into
the turn at its next tool boundary — a correction reaches the turn it
corrects. When no run is live (or it stopped reading), the message fires
as a run of its own; the duplicate claim covers it either way.GOLEM_ASK_USER_TTL idea, passed programmatically here via
WithQuestionTTL).The connector keeps no state of its own beyond the clock: everything durable lives in the store you pass it.