Background ConsolidatorWorker dispatches consolidation work to a Claude Code agent through harness.Harness.Execute (NOT via system DMs — per feedback_system_dm_no_trigger.md) with a one-time 15m dispatch token. The dispatched agent uses six new MCP tools, all token-gated and recording every action to memory_consolidation_jobs.actions JSON. Stores: - memory_links.go (+ test): typed edges with actor-prefix reserved-type guard; AddConsolidationLink bypass for memory_mark_duplicate / memory_supersede (their contractual writers). - memory_pins.go (+ test): owner pin overlay, bypasses score floor. - memory_status.go: queries the memory_status view. - consolidation_jobs.go: Create / Dispatch / Lease / AppendAction / Complete with ErrJobAlreadyInFlight via partial unique index. - auto_links.go: MessageListener generating mention / reply_to / channel_cooccurrence links automatically on send. Worker: - consolidator.go (+ test): ticker pattern modeled on StalemateWorker. Watermark trigger for link_gen / dedup_contradiction; daily 03:00 UTC for sleep-time core rewrite. Wallclock budget via harness Budget. Global semaphore gates concurrent owners. Mocked-harness test asserts no system DM is ever sent. - consolidator_prompts.go: four job-type prompts passed via env to the dispatched agent. MCP tools (internal/mcp/memory_tools.go + test): - memory_list_unprocessed, memory_write_reflection, memory_rewrite_core, memory_mark_duplicate, memory_supersede, memory_add_link. - Full error-code matrix tested per contracts/mcp-memory-tools.md. - Registered only when SYNAPBUS_DREAM_ENABLED=1. Injection extensions: - search/injection.go: pin overlay applied after retrieval; status filter drops soft_deleted / superseded unless pinned. New PinProvider, StatusProvider, MessageLookup hooks on InjectionOpts. Wiring: - cmd/synapbus/main.go: stores constructed, AutoLinkListener attached to MessagingService, mcpSrv.SetDream wired, ConsolidatorWorker start/stop, admin DreamRun closure. - cmd/synapbus/admin.go: synapbus memory dream-run --owner --job socket-RPC command (forces a single job bypassing trigger). Cycle workarounds (documented in code): - messaging.DreamAgent / HarnessDispatcher are local interfaces (the agents and harness packages import messaging, not the reverse). main.go wraps the real types via adapter structs. Stubbed: - Cron expression parsing (DreamDeepCron). Hardcoded daily 03:00 UTC. Adding robfig/cron deferred to keep no-new-deps. Pre-existing reactor test failures (5) are unchanged; confirmed pre-020 via stash check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
95 lines
3.5 KiB
Go
95 lines
3.5 KiB
Go
// Package admin provides a Unix domain socket server for local administration.
|
|
package admin
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"log/slog"
|
|
"net"
|
|
|
|
"github.com/synapbus/synapbus/internal/agents"
|
|
"github.com/synapbus/synapbus/internal/attachments"
|
|
"github.com/synapbus/synapbus/internal/auth"
|
|
"github.com/synapbus/synapbus/internal/channels"
|
|
"github.com/synapbus/synapbus/internal/k8s"
|
|
"github.com/synapbus/synapbus/internal/messaging"
|
|
"github.com/synapbus/synapbus/internal/search"
|
|
"github.com/synapbus/synapbus/internal/trace"
|
|
"github.com/synapbus/synapbus/internal/webhooks"
|
|
)
|
|
|
|
// WebhookServiceProvider defines the webhook operations needed by the admin socket.
|
|
type WebhookServiceProvider interface {
|
|
RegisterWebhook(ctx context.Context, agentName, url string, events []string, secret string) (*webhooks.Webhook, error)
|
|
ListWebhooks(ctx context.Context, agentName string) ([]*webhooks.Webhook, error)
|
|
DeleteWebhook(ctx context.Context, agentName string, webhookID int64) error
|
|
}
|
|
|
|
// K8sServiceProvider defines the K8s handler operations needed by the admin socket.
|
|
type K8sServiceProvider interface {
|
|
RegisterHandler(ctx context.Context, agentName string, req k8s.RegisterHandlerRequest) (*k8s.K8sHandler, error)
|
|
ListHandlers(ctx context.Context, agentName string) ([]*k8s.K8sHandler, error)
|
|
DeleteHandler(ctx context.Context, agentName string, handlerID int64) error
|
|
}
|
|
|
|
// Services holds references to all services the admin socket can control.
|
|
type Services struct {
|
|
Users *auth.SQLiteUserStore
|
|
Sessions auth.SessionStore
|
|
Agents *agents.AgentService
|
|
Messages *messaging.MessagingService
|
|
Channels *channels.Service
|
|
Traces trace.TraceStore
|
|
EmbeddingStore *search.EmbeddingStore
|
|
VectorIndex *search.VectorIndex
|
|
SearchService *search.Service
|
|
AttachmentService *attachments.Service
|
|
WebhookService WebhookServiceProvider
|
|
K8sService K8sServiceProvider
|
|
DataDir string
|
|
RetentionWorker RetentionStatusProvider
|
|
|
|
// CoreMemoryStore is the per-(owner, agent) core memory store wired
|
|
// in for feature 020 admin CLI commands (`synapbus memory core ...`).
|
|
// May be nil — handlers report "core memory store not configured".
|
|
CoreMemoryStore *messaging.CoreMemoryStore
|
|
|
|
// DreamRun, when non-nil, dispatches a single consolidation job
|
|
// bypassing the trigger check. Wired by main.go when the
|
|
// consolidator worker is enabled. Closure form keeps the worker
|
|
// internals out of the admin package's import graph.
|
|
DreamRun func(ctx context.Context, ownerID, jobType string) (jobID int64, err error)
|
|
}
|
|
|
|
// RetentionStatusProvider provides retention status information.
|
|
type RetentionStatusProvider interface {
|
|
Status() map[string]interface{}
|
|
}
|
|
|
|
// AdminServer is a Unix domain socket server for local administration.
|
|
type AdminServer struct {
|
|
listener net.Listener
|
|
db *sql.DB
|
|
services *Services
|
|
logger *slog.Logger
|
|
socketPath string
|
|
done chan struct{}
|
|
}
|
|
|
|
// NewServer creates a new admin server bound to a Unix socket at {dataDir}/synapbus.sock.
|
|
// If socketPath is non-empty it overrides the default.
|
|
func NewServer(socketPath string, db *sql.DB, services *Services, logger *slog.Logger) *AdminServer {
|
|
return &AdminServer{
|
|
db: db,
|
|
services: services,
|
|
logger: logger.With("component", "admin"),
|
|
socketPath: socketPath,
|
|
done: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// SocketPath returns the path to the Unix socket.
|
|
func (s *AdminServer) SocketPath() string {
|
|
return s.socketPath
|
|
}
|