Changeset 0.23.0 (#153)
This commit is contained in:
@@ -183,20 +183,40 @@ func (s *ChannelStore) SetCursor(ctx context.Context, channelID, userID, leafID
|
||||
}
|
||||
|
||||
func (s *ChannelStore) SetModel(ctx context.Context, cm *models.ChannelModel) error {
|
||||
// For persona entries, use the persona-aware path
|
||||
if cm.PersonaID != nil && *cm.PersonaID != "" {
|
||||
return s.SetPersonaModel(ctx, cm)
|
||||
}
|
||||
// Raw model upsert (no persona) — matches idx_channel_models_raw partial index
|
||||
_, err := DB.ExecContext(ctx, `
|
||||
INSERT INTO channel_models (channel_id, model_id, provider_config_id, display_name, system_prompt, settings, is_default)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
ON CONFLICT (channel_id, model_id) DO UPDATE SET
|
||||
provider_config_id = $3, display_name = $4, system_prompt = $5, settings = $6, is_default = $7`,
|
||||
ON CONFLICT (channel_id, model_id, provider_config_id) WHERE persona_id IS NULL DO UPDATE SET
|
||||
display_name = $4, system_prompt = $5, settings = $6, is_default = $7`,
|
||||
cm.ChannelID, cm.ModelID, cm.ProviderConfigID, cm.DisplayName, cm.SystemPrompt, "{}", cm.IsDefault)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetPersonaModel inserts or updates a persona's channel model roster entry.
|
||||
// Uses the idx_channel_models_persona partial index (one per persona per channel).
|
||||
func (s *ChannelStore) SetPersonaModel(ctx context.Context, cm *models.ChannelModel) error {
|
||||
_, err := DB.ExecContext(ctx, `
|
||||
INSERT INTO channel_models (channel_id, model_id, provider_config_id, persona_id, display_name, system_prompt, settings, is_default)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
ON CONFLICT (channel_id, persona_id) WHERE persona_id IS NOT NULL DO UPDATE SET
|
||||
model_id = $2, provider_config_id = $3, display_name = $5, system_prompt = $6, settings = $7, is_default = $8`,
|
||||
cm.ChannelID, cm.ModelID, cm.ProviderConfigID, cm.PersonaID, cm.DisplayName, cm.SystemPrompt, "{}", cm.IsDefault)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ChannelStore) GetModels(ctx context.Context, channelID string) ([]models.ChannelModel, error) {
|
||||
rows, err := DB.QueryContext(ctx, `
|
||||
SELECT id, channel_id, model_id, COALESCE(provider_config_id::text, ''),
|
||||
COALESCE(display_name, ''), COALESCE(system_prompt, ''), is_default
|
||||
FROM channel_models WHERE channel_id = $1`, channelID)
|
||||
SELECT cm.id, cm.channel_id, cm.model_id, COALESCE(cm.provider_config_id::text, ''),
|
||||
COALESCE(cm.persona_id::text, ''), COALESCE(p.handle, ''), COALESCE(cm.display_name, ''),
|
||||
COALESCE(cm.system_prompt, ''), cm.is_default
|
||||
FROM channel_models cm
|
||||
LEFT JOIN personas p ON p.id = cm.persona_id
|
||||
WHERE cm.channel_id = $1`, channelID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -205,10 +225,14 @@ func (s *ChannelStore) GetModels(ctx context.Context, channelID string) ([]model
|
||||
var result []models.ChannelModel
|
||||
for rows.Next() {
|
||||
var cm models.ChannelModel
|
||||
var personaID string
|
||||
if err := rows.Scan(&cm.ID, &cm.ChannelID, &cm.ModelID, &cm.ProviderConfigID,
|
||||
&cm.DisplayName, &cm.SystemPrompt, &cm.IsDefault); err != nil {
|
||||
&personaID, &cm.Handle, &cm.DisplayName, &cm.SystemPrompt, &cm.IsDefault); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if personaID != "" {
|
||||
cm.PersonaID = &personaID
|
||||
}
|
||||
result = append(result, cm)
|
||||
}
|
||||
return result, rows.Err()
|
||||
@@ -216,15 +240,22 @@ func (s *ChannelStore) GetModels(ctx context.Context, channelID string) ([]model
|
||||
|
||||
func (s *ChannelStore) GetModelByID(ctx context.Context, id string) (*models.ChannelModel, error) {
|
||||
var cm models.ChannelModel
|
||||
var personaID string
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT id, channel_id, model_id, COALESCE(provider_config_id::text, ''),
|
||||
COALESCE(display_name, ''), COALESCE(system_prompt, ''), is_default
|
||||
FROM channel_models WHERE id = $1`, id).Scan(
|
||||
SELECT cm.id, cm.channel_id, cm.model_id, COALESCE(cm.provider_config_id::text, ''),
|
||||
COALESCE(cm.persona_id::text, ''), COALESCE(p.handle, ''), COALESCE(cm.display_name, ''),
|
||||
COALESCE(cm.system_prompt, ''), cm.is_default
|
||||
FROM channel_models cm
|
||||
LEFT JOIN personas p ON p.id = cm.persona_id
|
||||
WHERE cm.id = $1`, id).Scan(
|
||||
&cm.ID, &cm.ChannelID, &cm.ModelID, &cm.ProviderConfigID,
|
||||
&cm.DisplayName, &cm.SystemPrompt, &cm.IsDefault)
|
||||
&personaID, &cm.Handle, &cm.DisplayName, &cm.SystemPrompt, &cm.IsDefault)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if personaID != "" {
|
||||
cm.PersonaID = &personaID
|
||||
}
|
||||
return &cm, nil
|
||||
}
|
||||
|
||||
@@ -287,3 +318,99 @@ func (s *ChannelStore) ResolveWorkspaceID(ctx context.Context, channelID string)
|
||||
}
|
||||
return NullableString(wsID), nil
|
||||
}
|
||||
|
||||
// ── Channel Participants (ICD §3.7) ──────────
|
||||
|
||||
func (s *ChannelStore) AddParticipant(ctx context.Context, p *models.ChannelParticipant) error {
|
||||
_, err := DB.ExecContext(ctx, `
|
||||
INSERT INTO channel_participants (channel_id, participant_type, participant_id, role, display_name, avatar_url)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)`,
|
||||
p.ChannelID, p.ParticipantType, p.ParticipantID, p.Role, p.DisplayName, p.AvatarURL)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ChannelStore) ListParticipants(ctx context.Context, channelID string) ([]models.ChannelParticipant, error) {
|
||||
rows, err := DB.QueryContext(ctx, `
|
||||
SELECT id, channel_id, participant_type, participant_id, role,
|
||||
display_name, avatar_url, joined_at
|
||||
FROM channel_participants WHERE channel_id = $1 ORDER BY joined_at`, channelID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var result []models.ChannelParticipant
|
||||
for rows.Next() {
|
||||
var p models.ChannelParticipant
|
||||
if err := rows.Scan(&p.ID, &p.ChannelID, &p.ParticipantType, &p.ParticipantID,
|
||||
&p.Role, &p.DisplayName, &p.AvatarURL, &p.JoinedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *ChannelStore) GetParticipantByID(ctx context.Context, id string) (*models.ChannelParticipant, error) {
|
||||
var p models.ChannelParticipant
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT id, channel_id, participant_type, participant_id, role,
|
||||
display_name, avatar_url, joined_at
|
||||
FROM channel_participants WHERE id = $1`, id).Scan(
|
||||
&p.ID, &p.ChannelID, &p.ParticipantType, &p.ParticipantID,
|
||||
&p.Role, &p.DisplayName, &p.AvatarURL, &p.JoinedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (s *ChannelStore) UpdateParticipantRole(ctx context.Context, id, role string) error {
|
||||
_, err := DB.ExecContext(ctx, `UPDATE channel_participants SET role = $1 WHERE id = $2`, role, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ChannelStore) RemoveParticipant(ctx context.Context, id string) error {
|
||||
res, err := DB.ExecContext(ctx, `DELETE FROM channel_participants WHERE id = $1`, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, _ := res.RowsAffected()
|
||||
if n == 0 {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ChannelStore) IsParticipant(ctx context.Context, channelID, pType, pID string) (bool, error) {
|
||||
var exists bool
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT EXISTS(SELECT 1 FROM channel_participants
|
||||
WHERE channel_id = $1 AND participant_type = $2 AND participant_id = $3)`,
|
||||
channelID, pType, pID).Scan(&exists)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
func (s *ChannelStore) GetParticipantRole(ctx context.Context, channelID, pType, pID string) (string, error) {
|
||||
var role string
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT role FROM channel_participants
|
||||
WHERE channel_id = $1 AND participant_type = $2 AND participant_id = $3`,
|
||||
channelID, pType, pID).Scan(&role)
|
||||
return role, err
|
||||
}
|
||||
|
||||
func (s *ChannelStore) CountParticipantsByRole(ctx context.Context, channelID, role string) (int, error) {
|
||||
var count int
|
||||
err := DB.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*) FROM channel_participants WHERE channel_id = $1 AND role = $2`,
|
||||
channelID, role).Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
func (s *ChannelStore) DeleteModelByPersona(ctx context.Context, channelID, personaID string) error {
|
||||
_, err := DB.ExecContext(ctx,
|
||||
`DELETE FROM channel_models WHERE channel_id = $1 AND persona_id = $2`,
|
||||
channelID, personaID)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user