Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
181 lines
5.6 KiB
Go
181 lines
5.6 KiB
Go
package storesqlite
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
)
|
|
|
|
func (s *Store) ListSessionMessages(
|
|
ctx context.Context,
|
|
input ListSessionMessagesInput,
|
|
) (MessagePage, bool, error) {
|
|
if s == nil || s.db == nil {
|
|
return MessagePage{}, false, errors.New("workspace database is not initialized")
|
|
}
|
|
workspaceID := strings.TrimSpace(input.WorkspaceID)
|
|
agentSessionID := strings.TrimSpace(input.AgentSessionID)
|
|
if workspaceID == "" || agentSessionID == "" {
|
|
return MessagePage{}, false, nil
|
|
}
|
|
if _, ok, err := s.GetSession(ctx, workspaceID, agentSessionID); err != nil || !ok {
|
|
return MessagePage{}, ok, err
|
|
}
|
|
|
|
queryLimit := input.Limit
|
|
if queryLimit > 0 {
|
|
queryLimit++
|
|
}
|
|
turnID := strings.TrimSpace(input.TurnID)
|
|
messageID := strings.TrimSpace(input.MessageID)
|
|
where := []string{
|
|
"workspace_id = ?",
|
|
"agent_session_id = ?",
|
|
"deleted_at_unix_ms = 0",
|
|
`(
|
|
COALESCE(TRIM(turn_id), '') = ''
|
|
OR NOT EXISTS (
|
|
SELECT 1 FROM workspace_agent_turn_history history
|
|
WHERE history.workspace_id = workspace_agent_messages.workspace_id
|
|
AND history.agent_session_id = workspace_agent_messages.agent_session_id
|
|
AND history.turn_id = workspace_agent_messages.turn_id
|
|
AND history.history_state = 'retracted'
|
|
)
|
|
)`,
|
|
}
|
|
args := []any{workspaceID, agentSessionID}
|
|
if messageID != "" {
|
|
where = append(where, "message_id = ?")
|
|
args = append(args, messageID)
|
|
}
|
|
if turnID != "" {
|
|
where = append(where, "turn_id = ?")
|
|
args = append(args, turnID)
|
|
}
|
|
order := input.Order
|
|
if order == "" {
|
|
order = MessageOrderAsc
|
|
}
|
|
var rows *sql.Rows
|
|
var err error
|
|
switch order {
|
|
case MessageOrderDesc:
|
|
if input.BeforeVersion > 0 {
|
|
whereWithCursor := append(append([]string{}, where...), "version < ?")
|
|
argsWithCursor := append(append([]any{}, args...), input.BeforeVersion, queryLimit)
|
|
rows, err = s.db.QueryContext(ctx, `
|
|
SELECT id, agent_session_id, message_id, version, turn_id, role, kind, status,
|
|
semantics_json, payload_json, occurred_at_unix_ms, started_at_unix_ms, completed_at_unix_ms,
|
|
created_at_unix_ms, updated_at_unix_ms
|
|
FROM workspace_agent_messages
|
|
WHERE `+strings.Join(whereWithCursor, " AND ")+`
|
|
ORDER BY version DESC, id DESC
|
|
LIMIT ?
|
|
`, argsWithCursor...)
|
|
} else {
|
|
argsWithLimit := append(append([]any{}, args...), queryLimit)
|
|
rows, err = s.db.QueryContext(ctx, `
|
|
SELECT id, agent_session_id, message_id, version, turn_id, role, kind, status,
|
|
semantics_json, payload_json, occurred_at_unix_ms, started_at_unix_ms, completed_at_unix_ms,
|
|
created_at_unix_ms, updated_at_unix_ms
|
|
FROM workspace_agent_messages
|
|
WHERE `+strings.Join(where, " AND ")+`
|
|
ORDER BY version DESC, id DESC
|
|
LIMIT ?
|
|
`, argsWithLimit...)
|
|
}
|
|
case MessageOrderAsc:
|
|
whereWithCursor := append(append([]string{}, where...), "version > ?")
|
|
argsWithCursor := append(append([]any{}, args...), input.AfterVersion, queryLimit)
|
|
rows, err = s.db.QueryContext(ctx, `
|
|
SELECT id, agent_session_id, message_id, version, turn_id, role, kind, status,
|
|
semantics_json, payload_json, occurred_at_unix_ms, started_at_unix_ms, completed_at_unix_ms,
|
|
created_at_unix_ms, updated_at_unix_ms
|
|
FROM workspace_agent_messages
|
|
WHERE `+strings.Join(whereWithCursor, " AND ")+`
|
|
ORDER BY version ASC, id ASC
|
|
LIMIT ?
|
|
`, argsWithCursor...)
|
|
default:
|
|
return MessagePage{}, false, fmt.Errorf("unsupported workspace agent message order: %s", order)
|
|
}
|
|
if err != nil {
|
|
slog.Warn("workspace agent messages query failed",
|
|
"event", "workspace.agent_session.messages.sqlite.query_failed",
|
|
"workspace_id", workspaceID,
|
|
"agent_session_id", agentSessionID,
|
|
"after_version", input.AfterVersion,
|
|
"before_version", input.BeforeVersion,
|
|
"order", order,
|
|
"limit", input.Limit,
|
|
"query_limit", queryLimit,
|
|
"error", err,
|
|
)
|
|
return MessagePage{}, false, fmt.Errorf("list workspace agent messages: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
messages := make([]Message, 0)
|
|
for rows.Next() {
|
|
message, err := scanAgentMessage(rows)
|
|
if err != nil {
|
|
slog.Warn("workspace agent message row scan failed",
|
|
"event", "workspace.agent_session.messages.sqlite.scan_failed",
|
|
"workspace_id", workspaceID,
|
|
"agent_session_id", agentSessionID,
|
|
"after_version", input.AfterVersion,
|
|
"before_version", input.BeforeVersion,
|
|
"order", order,
|
|
"limit", input.Limit,
|
|
"query_limit", queryLimit,
|
|
"scanned_message_count", len(messages),
|
|
"error", err,
|
|
)
|
|
return MessagePage{}, false, err
|
|
}
|
|
messages = append(messages, message)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
slog.Warn("workspace agent messages row iteration failed",
|
|
"event", "workspace.agent_session.messages.sqlite.iterate_failed",
|
|
"workspace_id", workspaceID,
|
|
"agent_session_id", agentSessionID,
|
|
"after_version", input.AfterVersion,
|
|
"before_version", input.BeforeVersion,
|
|
"order", order,
|
|
"limit", input.Limit,
|
|
"query_limit", queryLimit,
|
|
"scanned_message_count", len(messages),
|
|
"error", err,
|
|
)
|
|
return MessagePage{}, false, fmt.Errorf("iterate workspace agent messages: %w", err)
|
|
}
|
|
if err := rows.Close(); err != nil {
|
|
return MessagePage{}, false,
|
|
fmt.Errorf("close workspace agent message rows: %w", err)
|
|
}
|
|
hasMore := false
|
|
if input.Limit > 0 && len(messages) > input.Limit {
|
|
hasMore = true
|
|
messages = messages[:input.Limit]
|
|
}
|
|
latestVersion := input.AfterVersion
|
|
if order == MessageOrderDesc {
|
|
latestVersion = 0
|
|
}
|
|
for _, message := range messages {
|
|
if message.Version > latestVersion {
|
|
latestVersion = message.Version
|
|
}
|
|
}
|
|
return MessagePage{
|
|
AgentSessionID: agentSessionID,
|
|
Messages: messages,
|
|
LatestVersion: latestVersion,
|
|
HasMore: hasMore,
|
|
}, true, nil
|
|
}
|