feat: Misskey channel adapter, agent reliability hardening & stream error resilience (#359)

This commit is contained in:
KasuganoSora
2026-04-13 17:10:50 +08:00
committed by GitHub
parent 26b01cc463
commit a40207ab6d
87 changed files with 3972 additions and 547 deletions
+36 -15
View File
@@ -35,6 +35,7 @@ import (
"github.com/memohai/memoh/internal/channel/adapters/feishu"
"github.com/memohai/memoh/internal/channel/adapters/local"
"github.com/memohai/memoh/internal/channel/adapters/matrix"
"github.com/memohai/memoh/internal/channel/adapters/misskey"
"github.com/memohai/memoh/internal/channel/adapters/qq"
"github.com/memohai/memoh/internal/channel/adapters/telegram"
"github.com/memohai/memoh/internal/channel/adapters/wechatoa"
@@ -361,12 +362,13 @@ func provideWorkspaceManager(log *slog.Logger, service ctr.Service, cfg config.C
// memory providers
// ---------------------------------------------------------------------------
func provideMemoryLLM(modelsService *models.Service, queries *dbsqlc.Queries, log *slog.Logger) memprovider.LLM {
func provideMemoryLLM(modelsService *models.Service, settingsService *settings.Service, queries *dbsqlc.Queries, log *slog.Logger) memprovider.LLM {
return &lazyLLMClient{
modelsService: modelsService,
queries: queries,
timeout: 30 * time.Second,
logger: log,
modelsService: modelsService,
settingsService: settingsService,
queries: queries,
timeout: 30 * time.Second,
logger: log,
}
}
@@ -531,6 +533,10 @@ func provideChannelRegistry(log *slog.Logger, hub *local.RouteHub, mediaService
weixinAdapter.SetAssetOpener(mediaService)
registry.MustRegister(weixinAdapter)
registry.MustRegister(local.NewWebAdapter(hub))
// Misskey
registry.MustRegister(misskey.NewMisskeyAdapter(log))
return registry
}
@@ -1084,14 +1090,15 @@ func ensureAdminUser(ctx context.Context, log *slog.Logger, queries *dbsqlc.Quer
// ---------------------------------------------------------------------------
type lazyLLMClient struct {
modelsService *models.Service
queries *dbsqlc.Queries
timeout time.Duration
logger *slog.Logger
modelsService *models.Service
settingsService *settings.Service
queries *dbsqlc.Queries
timeout time.Duration
logger *slog.Logger
}
func (c *lazyLLMClient) Extract(ctx context.Context, req memprovider.ExtractRequest) (memprovider.ExtractResponse, error) {
client, err := c.resolve(ctx)
client, err := c.resolve(ctx, req.BotID)
if err != nil {
return memprovider.ExtractResponse{}, err
}
@@ -1099,7 +1106,7 @@ func (c *lazyLLMClient) Extract(ctx context.Context, req memprovider.ExtractRequ
}
func (c *lazyLLMClient) Decide(ctx context.Context, req memprovider.DecideRequest) (memprovider.DecideResponse, error) {
client, err := c.resolve(ctx)
client, err := c.resolve(ctx, req.BotID)
if err != nil {
return memprovider.DecideResponse{}, err
}
@@ -1107,7 +1114,7 @@ func (c *lazyLLMClient) Decide(ctx context.Context, req memprovider.DecideReques
}
func (c *lazyLLMClient) Compact(ctx context.Context, req memprovider.CompactRequest) (memprovider.CompactResponse, error) {
client, err := c.resolve(ctx)
client, err := c.resolve(ctx, "")
if err != nil {
return memprovider.CompactResponse{}, err
}
@@ -1115,18 +1122,32 @@ func (c *lazyLLMClient) Compact(ctx context.Context, req memprovider.CompactRequ
}
func (c *lazyLLMClient) DetectLanguage(ctx context.Context, text string) (string, error) {
client, err := c.resolve(ctx)
client, err := c.resolve(ctx, "")
if err != nil {
return "", err
}
return client.DetectLanguage(ctx, text)
}
func (c *lazyLLMClient) resolve(ctx context.Context) (memprovider.LLM, error) {
func (c *lazyLLMClient) resolve(ctx context.Context, botID string) (memprovider.LLM, error) {
if c.modelsService == nil || c.queries == nil {
return nil, errors.New("models service not configured")
}
memoryModel, memoryProvider, err := models.SelectMemoryModelForBot(ctx, c.modelsService, c.queries, "")
// Try to use the bot's configured chat model for memory operations.
chatModelID := ""
if c.settingsService != nil && strings.TrimSpace(botID) != "" {
if botSettings, err := c.settingsService.GetBot(ctx, botID); err == nil {
// Prefer compaction model (smaller/cheaper), then chat model.
if id := strings.TrimSpace(botSettings.CompactionModelID); id != "" {
chatModelID = id
} else if id := strings.TrimSpace(botSettings.ChatModelID); id != "" {
chatModelID = id
}
}
}
memoryModel, memoryProvider, err := models.SelectMemoryModelForBot(ctx, c.modelsService, c.queries, chatModelID)
if err != nil {
return nil, err
}