Files
Memoh/internal/db/sqlc/models.go
T
BBQ 9ceabf68c4 feat(mcp): replace bind-mount+exec with in-container gRPC service (#179)
Replace the host bind-mount + containerd exec approach with a per-bot
in-container gRPC server (ContainerService, port 9090). All file I/O,
exec, and MCP stdio sessions now go through gRPC instead of running
shell commands or reading host-mounted directories.

Architecture changes:
- cmd/mcp: rewritten as a gRPC server (ContainerService) with full
  file and exec API (ReadFile, WriteFile, ListDir, ReadRaw, WriteRaw,
  Exec, Stat, Mkdir, Rename, DeleteFile)
- internal/mcp/mcpcontainer: protobuf definitions and generated stubs
- internal/mcp/mcpclient: gRPC client wrapper with connection pool
  (Pool) and Provider interface for dependency injection
- mcp.Manager: add per-bot IP cache, gRPC connection pool, and
  SetContainerIP/MCPClient methods; remove DataDir/Exec helpers
- containerd.Service: remove ExecTask/ExecTaskStreaming; network setup
  now returns NetworkResult{IP} for pool routing
- internal/fs/service.go: deleted (replaced by mcpclient)
- handlers/fs.go: deleted; MCP stdio session logic moved to mcp_stdio.go
- container provider Executor: all tools (read/write/list/edit/exec)
  now call gRPC client instead of running shell via exec
- storefs, containerfs, media, skills, memory: all I/O ported to
  mcpclient.Provider

Database:
- migration 0022: drop host_path column from containers table

One-time data migration:
- migrateBindMountData: on first Start() after upgrade, copies old
  bind-mount data into the container via gRPC, then renames src dir
  to prevent re-migration; runs in background goroutine

Bug fixes:
- mcp_stdio: callRaw now returns full JSON-RPC envelope
  {"jsonrpc","id","result"|"error"} matching protocol spec;
  explicit "initialize" call now advances session init state to
  prevent duplicate handshake on next non-initialize call
- mcpclient Pool: properly evict stale gRPC connection after snapshot
  replace (container process recreated); use SetContainerIP instead
  of direct map write so IP changes always evict pool entry
- migrateBindMountData: walkErr on directories now counted as failure
  so partially-walked trees don't get incorrectly marked as migrated
- cmd/mcp/Dockerfile: removed dead file (docker/Dockerfile.mcp is the
  canonical production build)

Tests:
- provider_test.go: restored with bufconn in-process gRPC mock
  (fakeContainerService + staticProvider), 14 cases covering all 5
  tools plus edge cases
- mcp_session_test.go: new, covers JSON-RPC envelope, init state
  machine, pending cleanup on cancel/close, readLoop cancel
- storefs/service_test.go: restored (pure function roundtrip tests)
2026-03-04 21:50:08 +08:00

419 lines
18 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
package sqlc
import (
"github.com/jackc/pgx/v5/pgtype"
)
type Bot struct {
ID pgtype.UUID `json:"id"`
OwnerUserID pgtype.UUID `json:"owner_user_id"`
Type string `json:"type"`
DisplayName pgtype.Text `json:"display_name"`
AvatarUrl pgtype.Text `json:"avatar_url"`
IsActive bool `json:"is_active"`
Status string `json:"status"`
MaxContextLoadTime int32 `json:"max_context_load_time"`
MaxContextTokens int32 `json:"max_context_tokens"`
Language string `json:"language"`
AllowGuest bool `json:"allow_guest"`
ReasoningEnabled bool `json:"reasoning_enabled"`
ReasoningEffort string `json:"reasoning_effort"`
MaxInboxItems int32 `json:"max_inbox_items"`
ChatModelID pgtype.UUID `json:"chat_model_id"`
SearchProviderID pgtype.UUID `json:"search_provider_id"`
MemoryProviderID pgtype.UUID `json:"memory_provider_id"`
HeartbeatEnabled bool `json:"heartbeat_enabled"`
HeartbeatInterval int32 `json:"heartbeat_interval"`
HeartbeatPrompt string `json:"heartbeat_prompt"`
HeartbeatModelID pgtype.UUID `json:"heartbeat_model_id"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type BotChannelConfig struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
ChannelType string `json:"channel_type"`
Credentials []byte `json:"credentials"`
ExternalIdentity pgtype.Text `json:"external_identity"`
SelfIdentity []byte `json:"self_identity"`
Routing []byte `json:"routing"`
Capabilities []byte `json:"capabilities"`
Disabled bool `json:"disabled"`
VerifiedAt pgtype.Timestamptz `json:"verified_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type BotChannelRoute struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
ChannelType string `json:"channel_type"`
ChannelConfigID pgtype.UUID `json:"channel_config_id"`
ExternalConversationID string `json:"external_conversation_id"`
ExternalThreadID pgtype.Text `json:"external_thread_id"`
ConversationType pgtype.Text `json:"conversation_type"`
DefaultReplyTarget pgtype.Text `json:"default_reply_target"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type BotEmailBinding struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
EmailProviderID pgtype.UUID `json:"email_provider_id"`
EmailAddress string `json:"email_address"`
CanRead bool `json:"can_read"`
CanWrite bool `json:"can_write"`
CanDelete bool `json:"can_delete"`
Config []byte `json:"config"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type BotHeartbeatLog struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
Status string `json:"status"`
ResultText string `json:"result_text"`
ErrorMessage string `json:"error_message"`
Usage []byte `json:"usage"`
ModelID pgtype.UUID `json:"model_id"`
StartedAt pgtype.Timestamptz `json:"started_at"`
CompletedAt pgtype.Timestamptz `json:"completed_at"`
}
type BotHistoryMessage struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
RouteID pgtype.UUID `json:"route_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderAccountUserID pgtype.UUID `json:"sender_account_user_id"`
ChannelType pgtype.Text `json:"channel_type"`
SourceMessageID pgtype.Text `json:"source_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
ModelID pgtype.UUID `json:"model_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type BotHistoryMessageAsset struct {
ID pgtype.UUID `json:"id"`
MessageID pgtype.UUID `json:"message_id"`
Role string `json:"role"`
Ordinal int32 `json:"ordinal"`
ContentHash string `json:"content_hash"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type BotInbox struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
Source string `json:"source"`
Header []byte `json:"header"`
Content string `json:"content"`
Action string `json:"action"`
IsRead bool `json:"is_read"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
ReadAt pgtype.Timestamptz `json:"read_at"`
}
type BotMember struct {
BotID pgtype.UUID `json:"bot_id"`
UserID pgtype.UUID `json:"user_id"`
Role string `json:"role"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type BotPreauthKey struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
Token string `json:"token"`
IssuedByUserID pgtype.UUID `json:"issued_by_user_id"`
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
UsedAt pgtype.Timestamptz `json:"used_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type BotStorageBinding struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
StorageProviderID pgtype.UUID `json:"storage_provider_id"`
BasePath string `json:"base_path"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type ChannelIdentity struct {
ID pgtype.UUID `json:"id"`
UserID pgtype.UUID `json:"user_id"`
ChannelType string `json:"channel_type"`
ChannelSubjectID string `json:"channel_subject_id"`
DisplayName pgtype.Text `json:"display_name"`
AvatarUrl pgtype.Text `json:"avatar_url"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type ChannelIdentityBindCode struct {
ID pgtype.UUID `json:"id"`
Token string `json:"token"`
IssuedByUserID pgtype.UUID `json:"issued_by_user_id"`
ChannelType pgtype.Text `json:"channel_type"`
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
UsedAt pgtype.Timestamptz `json:"used_at"`
UsedByChannelIdentityID pgtype.UUID `json:"used_by_channel_identity_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type Container struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
ContainerID string `json:"container_id"`
ContainerName string `json:"container_name"`
Image string `json:"image"`
Status string `json:"status"`
Namespace string `json:"namespace"`
AutoStart bool `json:"auto_start"`
ContainerPath string `json:"container_path"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
LastStartedAt pgtype.Timestamptz `json:"last_started_at"`
LastStoppedAt pgtype.Timestamptz `json:"last_stopped_at"`
}
type ContainerVersion struct {
ID pgtype.UUID `json:"id"`
ContainerID string `json:"container_id"`
SnapshotID pgtype.UUID `json:"snapshot_id"`
Version int32 `json:"version"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type EmailOutbox struct {
ID pgtype.UUID `json:"id"`
ProviderID pgtype.UUID `json:"provider_id"`
BotID pgtype.UUID `json:"bot_id"`
MessageID string `json:"message_id"`
FromAddress string `json:"from_address"`
ToAddresses []byte `json:"to_addresses"`
Subject string `json:"subject"`
BodyText string `json:"body_text"`
BodyHtml string `json:"body_html"`
Attachments []byte `json:"attachments"`
Status string `json:"status"`
Error string `json:"error"`
SentAt pgtype.Timestamptz `json:"sent_at"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type EmailProvider struct {
ID pgtype.UUID `json:"id"`
Name string `json:"name"`
Provider string `json:"provider"`
Config []byte `json:"config"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type LifecycleEvent struct {
ID string `json:"id"`
ContainerID string `json:"container_id"`
EventType string `json:"event_type"`
Payload []byte `json:"payload"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type LlmProvider struct {
ID pgtype.UUID `json:"id"`
Name string `json:"name"`
BaseUrl string `json:"base_url"`
ApiKey string `json:"api_key"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type McpConnection struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
Name string `json:"name"`
Type string `json:"type"`
Config []byte `json:"config"`
IsActive bool `json:"is_active"`
Status string `json:"status"`
ToolsCache []byte `json:"tools_cache"`
LastProbedAt pgtype.Timestamptz `json:"last_probed_at"`
StatusMessage string `json:"status_message"`
AuthType string `json:"auth_type"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type McpOauthToken struct {
ID pgtype.UUID `json:"id"`
ConnectionID pgtype.UUID `json:"connection_id"`
ResourceMetadataUrl string `json:"resource_metadata_url"`
AuthorizationServerUrl string `json:"authorization_server_url"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
RegistrationEndpoint string `json:"registration_endpoint"`
ScopesSupported []string `json:"scopes_supported"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
Scope string `json:"scope"`
PkceCodeVerifier string `json:"pkce_code_verifier"`
StateParam string `json:"state_param"`
ResourceUri string `json:"resource_uri"`
RedirectUri string `json:"redirect_uri"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type MediaAsset struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
StorageProviderID pgtype.UUID `json:"storage_provider_id"`
ContentHash string `json:"content_hash"`
MediaType string `json:"media_type"`
Mime string `json:"mime"`
SizeBytes int64 `json:"size_bytes"`
StorageKey string `json:"storage_key"`
OriginalName pgtype.Text `json:"original_name"`
Width pgtype.Int4 `json:"width"`
Height pgtype.Int4 `json:"height"`
DurationMs pgtype.Int8 `json:"duration_ms"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type MemoryProvider struct {
ID pgtype.UUID `json:"id"`
Name string `json:"name"`
Provider string `json:"provider"`
Config []byte `json:"config"`
IsDefault bool `json:"is_default"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type Model struct {
ID pgtype.UUID `json:"id"`
ModelID string `json:"model_id"`
Name pgtype.Text `json:"name"`
LlmProviderID pgtype.UUID `json:"llm_provider_id"`
ClientType pgtype.Text `json:"client_type"`
Dimensions pgtype.Int4 `json:"dimensions"`
InputModalities []string `json:"input_modalities"`
SupportsReasoning bool `json:"supports_reasoning"`
Type string `json:"type"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type ModelVariant struct {
ID pgtype.UUID `json:"id"`
ModelUuid pgtype.UUID `json:"model_uuid"`
VariantID string `json:"variant_id"`
Weight int32 `json:"weight"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type Schedule struct {
ID pgtype.UUID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Pattern string `json:"pattern"`
MaxCalls pgtype.Int4 `json:"max_calls"`
CurrentCalls int32 `json:"current_calls"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
Enabled bool `json:"enabled"`
Command string `json:"command"`
BotID pgtype.UUID `json:"bot_id"`
}
type SearchProvider struct {
ID pgtype.UUID `json:"id"`
Name string `json:"name"`
Provider string `json:"provider"`
Config []byte `json:"config"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type Snapshot struct {
ID pgtype.UUID `json:"id"`
ContainerID string `json:"container_id"`
RuntimeSnapshotName string `json:"runtime_snapshot_name"`
ParentRuntimeSnapshotName pgtype.Text `json:"parent_runtime_snapshot_name"`
Snapshotter string `json:"snapshotter"`
Source string `json:"source"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type StorageProvider struct {
ID pgtype.UUID `json:"id"`
Name string `json:"name"`
Provider string `json:"provider"`
Config []byte `json:"config"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type Subagent struct {
ID pgtype.UUID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
Deleted bool `json:"deleted"`
DeletedAt pgtype.Timestamptz `json:"deleted_at"`
BotID pgtype.UUID `json:"bot_id"`
Messages []byte `json:"messages"`
Metadata []byte `json:"metadata"`
Skills []byte `json:"skills"`
Usage []byte `json:"usage"`
}
type User struct {
ID pgtype.UUID `json:"id"`
Username pgtype.Text `json:"username"`
Email pgtype.Text `json:"email"`
PasswordHash pgtype.Text `json:"password_hash"`
Role string `json:"role"`
DisplayName pgtype.Text `json:"display_name"`
AvatarUrl pgtype.Text `json:"avatar_url"`
DataRoot pgtype.Text `json:"data_root"`
LastLoginAt pgtype.Timestamptz `json:"last_login_at"`
IsActive bool `json:"is_active"`
Metadata []byte `json:"metadata"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}
type UserChannelBinding struct {
ID pgtype.UUID `json:"id"`
UserID pgtype.UUID `json:"user_id"`
ChannelType string `json:"channel_type"`
Config []byte `json:"config"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
}