diff --git a/server/internal/integrations/octo/connector.go b/server/internal/integrations/octo/connector.go index 31ce7055c8..c0b8a78a79 100644 --- a/server/internal/integrations/octo/connector.go +++ b/server/internal/integrations/octo/connector.go @@ -10,7 +10,7 @@ import ( ) // socketConnector is the production Connector: it registers the bot over REST to -// obtain an im_token + ws_url, opens an transport.Socket, and bridges inbound messages +// obtain an im_token + ws_url, opens a transport.Socket, and bridges inbound messages // until the context is cancelled. Reconnect/backoff is handled inside transport.Socket. type socketConnector struct { installations *InstallationService diff --git a/server/internal/integrations/octo/doc.go b/server/internal/integrations/octo/doc.go index 75ef2e86ab..253f38ef73 100644 --- a/server/internal/integrations/octo/doc.go +++ b/server/internal/integrations/octo/doc.go @@ -2,14 +2,36 @@ // inbound message dispatch into chat sessions, outbound replies, identity // binding, and the WebSocket connection hub. // -// It builds on the WuKongIM transport layer in -// github.com/multica-ai/multica/server/internal/integrations/im and follows the -// same structural boundaries as the Lark integration -// (internal/integrations/lark): the dispatcher converts inbound IM messages into -// chat_session + chat_message rows and enqueues agent tasks via the shared -// TaskService; outbound replies are driven by chat:done / task:failed events. -// -// This file currently only declares the package; the implementation lands in -// later phases (dispatcher, outbound, binding, hub). The DB-layer queries it -// depends on are defined in pkg/db/queries/octo.sql (migration 119). +// It builds on the WuKongIM transport layer in the transport subpackage +// (github.com/multica-ai/multica/server/internal/integrations/octo/transport) +// and follows the same structural boundaries as the Lark integration +// (internal/integrations/lark). The layering is one-directional: +// +// transport — WuKongIM binary protocol (socket) + Octo REST client. No +// knowledge of business types. +// business — this package. Depends on transport and the generated DB +// queries, never the reverse. +// +// The moving parts: +// +// - Hub (hub.go) owns one WebSocket connection per active installation, +// coordinated across replicas by a DB lease. It bridges each decoded +// message to the Dispatcher and forwards the verdict to the OutcomeReplier. +// - Dispatcher (dispatcher.go) converts an inbound message into +// chat_session + chat_message rows and enqueues an agent task via the +// shared service.TaskService, behind a two-phase dedup gate. +// - Patcher (outbound.go) relays the agent's reply back to Octo on +// chat:done / task:failed events. +// - OutcomeReplier (outcome_replier.go) handles the synchronous, pre-agent +// outcomes: DM an unbound sender a binding link, or notify the user when +// the agent is offline/archived. +// - BindingTokenService (binding_token.go) mints and redeems the one-shot +// tokens behind the {PublicURL}/octo/bind?token= flow. +// - InstallationService (client.go) creates/revokes installations and +// encrypts the bot token at rest. +// +// Expired binding tokens and stale inbound-dedup rows are purged by the +// octo_cleanup scheduler job (internal/scheduler/jobs_octo_cleanup.go). The +// DB-layer queries this package depends on are defined in +// pkg/db/queries/octo.sql (migration 119). package octo diff --git a/server/internal/integrations/octo/hub.go b/server/internal/integrations/octo/hub.go index 9be531eb65..b3e7a40f5c 100644 --- a/server/internal/integrations/octo/hub.go +++ b/server/internal/integrations/octo/hub.go @@ -41,7 +41,7 @@ type InboundHandler interface { // Connector is the per-installation transport. Run blocks until ctx is // cancelled (lease lost / shutdown) or the connection terminally fails. The -// production connector wraps an transport.Socket; tests provide a fake. +// production connector wraps a transport.Socket; tests provide a fake. type Connector interface { Run(ctx context.Context, inst db.OctoInstallation, onMessage func(transport.BotMessage)) error } diff --git a/server/internal/integrations/octo/types.go b/server/internal/integrations/octo/types.go index 3f6efe81d2..465885a230 100644 --- a/server/internal/integrations/octo/types.go +++ b/server/internal/integrations/octo/types.go @@ -39,11 +39,11 @@ const ( const BindingTokenTTL = 15 * time.Minute // InboundMessage is the dispatcher's input: a single Octo message already -// decoded by the transport layer (internal/integrations/im) and normalized into -// the fields the business pipeline needs. The bridge that owns the transport.Socket -// converts an transport.BotMessage into this shape (resolving robot_id → routing, -// computing AddressedToBot) so the dispatcher has no direct dependency on the -// transport package. +// decoded by the transport layer (internal/integrations/octo/transport) and +// normalized into the fields the business pipeline needs. The bridge that owns +// the transport.Socket converts a transport.BotMessage into this shape +// (resolving robot_id → routing, computing AddressedToBot) so the dispatcher +// has no direct dependency on the transport package. type InboundMessage struct { // RobotID identifies which bot received the event — the routing key to the // octo_installation row (octo_installation.robot_id).