mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add persisted whole-chat summary with background generation (#26657)
Adds a persisted whole-chat summary that backs the chat summary popover. A new nullable `chats.summary` column is populated in the background after a successful root-chat turn and pushed to clients via a new `chat_summary_change` watch event (distinct from `summary_change`, which is bound to `last_turn_summary`), so the popover reads `chat.summary` straight off the loaded `Chat` with no extra query. This is the data source for the popover and per-chat cost UI built in #26649; the popover can consume `chat.summary` once this lands (the field is nullable, so merge order does not matter). ## How it works - **Generation** runs in the existing successful-turn finalize hook, detached from the request so the user's turn is never blocked. A cadence gate generates the first summary after one completed turn, then regenerates every three turns, using the `chats.summary_generated_at` freshness marker. Generation reads compaction-aware history, renders it to a bounded plain-text transcript (short transcripts are skipped), and asks for a 1-3 sentence summary via structured output. Failures never clear an existing summary. - **Staleness** is guarded by `history_version` (mirroring `last_turn_summary`), so a background write racing a newer turn loses while worker lifecycle transitions cannot reject a fresh write. - **Model selection** uses the chat's configured model. ## Deferred to follow-ups - **Cost accounting**: the `chat_messages.cost_source` discriminator and summary/title usage recording were removed from this PR so summary persistence is not blocked by hidden accounting rows advancing `history_version`. Title usage recording stays on main's `InsertChatMessages` path. - **Model override**: deployment-wide summary generation model selection is split into #26803; the base feature always uses the chat model. ## Notes - Migration `000540` adds `chats.summary` and `chats.summary_generated_at`, and recreates `chats_expanded` to expose the new columns. - Root chats only; shared viewers pick up the summary on their next refetch (live watch events are owner-only). Refs #26649 --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Generated
+6
@@ -17012,6 +17012,10 @@ const docTemplate = `{
|
||||
"status": {
|
||||
"$ref": "#/definitions/codersdk.ChatStatus"
|
||||
},
|
||||
"summary": {
|
||||
"description": "Summary is the persisted whole-chat summary, generated in the background.\nIt is nil until the first summary has been produced.",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -18143,6 +18147,7 @@ const docTemplate = `{
|
||||
"enum": [
|
||||
"status_change",
|
||||
"summary_change",
|
||||
"chat_summary_change",
|
||||
"title_change",
|
||||
"created",
|
||||
"deleted",
|
||||
@@ -18153,6 +18158,7 @@ const docTemplate = `{
|
||||
"x-enum-varnames": [
|
||||
"ChatWatchEventKindStatusChange",
|
||||
"ChatWatchEventKindSummaryChange",
|
||||
"ChatWatchEventKindChatSummaryChange",
|
||||
"ChatWatchEventKindTitleChange",
|
||||
"ChatWatchEventKindCreated",
|
||||
"ChatWatchEventKindDeleted",
|
||||
|
||||
Generated
+6
@@ -15293,6 +15293,10 @@
|
||||
"status": {
|
||||
"$ref": "#/definitions/codersdk.ChatStatus"
|
||||
},
|
||||
"summary": {
|
||||
"description": "Summary is the persisted whole-chat summary, generated in the background.\nIt is nil until the first summary has been produced.",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -16371,6 +16375,7 @@
|
||||
"enum": [
|
||||
"status_change",
|
||||
"summary_change",
|
||||
"chat_summary_change",
|
||||
"title_change",
|
||||
"created",
|
||||
"deleted",
|
||||
@@ -16381,6 +16386,7 @@
|
||||
"x-enum-varnames": [
|
||||
"ChatWatchEventKindStatusChange",
|
||||
"ChatWatchEventKindSummaryChange",
|
||||
"ChatWatchEventKindChatSummaryChange",
|
||||
"ChatWatchEventKindTitleChange",
|
||||
"ChatWatchEventKindCreated",
|
||||
"ChatWatchEventKindDeleted",
|
||||
|
||||
@@ -1750,6 +1750,9 @@ func Chat(c database.Chat, diffStatus *database.ChatDiffStatus, files []database
|
||||
if c.LastTurnSummary.Valid {
|
||||
chat.LastTurnSummary = &c.LastTurnSummary.String
|
||||
}
|
||||
if c.Summary.Valid {
|
||||
chat.Summary = &c.Summary.String
|
||||
}
|
||||
if c.LastReasoningEffort.Valid {
|
||||
lastReasoningEffort := string(c.LastReasoningEffort.ChatReasoningEffort)
|
||||
chat.LastReasoningEffort = &lastReasoningEffort
|
||||
|
||||
@@ -713,6 +713,7 @@ func TestChat_AllFieldsPopulated(t *testing.T) {
|
||||
ClientType: database.ChatClientTypeUi,
|
||||
LastError: pqtype.NullRawMessage{RawMessage: lastErrorRaw, Valid: true},
|
||||
LastTurnSummary: sql.NullString{String: "turn completed", Valid: true},
|
||||
Summary: sql.NullString{String: "summarized the whole chat", Valid: true},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Archived: true,
|
||||
|
||||
@@ -7452,6 +7452,17 @@ func (q *querier) UpdateChatStatus(ctx context.Context, arg database.UpdateChatS
|
||||
return q.db.UpdateChatStatus(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateChatSummary(ctx context.Context, arg database.UpdateChatSummaryParams) (int64, error) {
|
||||
chat, err := q.db.GetChatByID(ctx, arg.ID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, chat); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return q.db.UpdateChatSummary(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpdateChatTitleByID(ctx context.Context, arg database.UpdateChatTitleByIDParams) (database.Chat, error) {
|
||||
chat, err := q.db.GetChatByID(ctx, arg.ID)
|
||||
if err != nil {
|
||||
|
||||
@@ -1917,6 +1917,17 @@ func (s *MethodTestSuite) TestChats() {
|
||||
dbm.EXPECT().UpdateChatLastTurnSummary(gomock.Any(), arg).Return(int64(1), nil).AnyTimes()
|
||||
check.Args(arg).Asserts(chat, policy.ActionUpdate).Returns(int64(1))
|
||||
}))
|
||||
s.Run("UpdateChatSummary", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
chat := testutil.Fake(s.T(), faker, database.Chat{})
|
||||
arg := database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: chat.HistoryVersion,
|
||||
Summary: sql.NullString{String: "summarized the whole chat", Valid: true},
|
||||
}
|
||||
dbm.EXPECT().GetChatByID(gomock.Any(), chat.ID).Return(chat, nil).AnyTimes()
|
||||
dbm.EXPECT().UpdateChatSummary(gomock.Any(), arg).Return(int64(1), nil).AnyTimes()
|
||||
check.Args(arg).Asserts(chat, policy.ActionUpdate).Returns(int64(1))
|
||||
}))
|
||||
s.Run("UpdateChatLastReadMessageID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
chat := testutil.Fake(s.T(), faker, database.Chat{})
|
||||
arg := database.UpdateChatLastReadMessageIDParams{
|
||||
|
||||
+8
@@ -5305,6 +5305,14 @@ func (m queryMetricsStore) UpdateChatStatus(ctx context.Context, arg database.Up
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) UpdateChatSummary(ctx context.Context, arg database.UpdateChatSummaryParams) (int64, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.UpdateChatSummary(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("UpdateChatSummary").Observe(time.Since(start).Seconds())
|
||||
m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "UpdateChatSummary").Inc()
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) UpdateChatTitleByID(ctx context.Context, arg database.UpdateChatTitleByIDParams) (database.Chat, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.UpdateChatTitleByID(ctx, arg)
|
||||
|
||||
Generated
+15
@@ -9996,6 +9996,21 @@ func (mr *MockStoreMockRecorder) UpdateChatStatus(ctx, arg any) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChatStatus", reflect.TypeOf((*MockStore)(nil).UpdateChatStatus), ctx, arg)
|
||||
}
|
||||
|
||||
// UpdateChatSummary mocks base method.
|
||||
func (m *MockStore) UpdateChatSummary(ctx context.Context, arg database.UpdateChatSummaryParams) (int64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateChatSummary", ctx, arg)
|
||||
ret0, _ := ret[0].(int64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdateChatSummary indicates an expected call of UpdateChatSummary.
|
||||
func (mr *MockStoreMockRecorder) UpdateChatSummary(ctx, arg any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChatSummary", reflect.TypeOf((*MockStore)(nil).UpdateChatSummary), ctx, arg)
|
||||
}
|
||||
|
||||
// UpdateChatTitleByID mocks base method.
|
||||
func (m *MockStore) UpdateChatTitleByID(ctx context.Context, arg database.UpdateChatTitleByIDParams) (database.Chat, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
Generated
+4
@@ -2097,6 +2097,8 @@ CREATE TABLE chats (
|
||||
context_error text DEFAULT ''::text NOT NULL,
|
||||
last_reasoning_effort chat_reasoning_effort,
|
||||
compaction_requested_at timestamp with time zone,
|
||||
summary text,
|
||||
summary_generated_at timestamp with time zone,
|
||||
CONSTRAINT chat_acl_only_on_root_chats CHECK ((((parent_chat_id IS NULL) AND (root_chat_id IS NULL)) OR ((user_acl = '{}'::jsonb) AND (group_acl = '{}'::jsonb)))),
|
||||
CONSTRAINT chat_group_acl_not_null_jsonb CHECK (((group_acl IS NOT NULL) AND (jsonb_typeof(group_acl) = 'object'::text))),
|
||||
CONSTRAINT chat_user_acl_not_null_jsonb CHECK (((user_acl IS NOT NULL) AND (jsonb_typeof(user_acl) = 'object'::text))),
|
||||
@@ -2202,6 +2204,8 @@ CREATE VIEW chats_expanded AS
|
||||
c.plan_mode,
|
||||
c.client_type,
|
||||
c.last_turn_summary,
|
||||
c.summary,
|
||||
c.summary_generated_at,
|
||||
c.snapshot_version,
|
||||
c.history_version,
|
||||
c.queue_version,
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
-- Drop the view before the columns it references, then recreate it without
|
||||
-- the summary columns, matching the 000549 chats_expanded definition.
|
||||
DROP VIEW IF EXISTS chats_expanded;
|
||||
|
||||
ALTER TABLE chats
|
||||
DROP COLUMN summary,
|
||||
DROP COLUMN summary_generated_at;
|
||||
|
||||
CREATE VIEW chats_expanded AS
|
||||
SELECT c.id,
|
||||
c.owner_id,
|
||||
c.workspace_id,
|
||||
c.title,
|
||||
c.status,
|
||||
c.worker_id,
|
||||
c.started_at,
|
||||
c.heartbeat_at,
|
||||
c.created_at,
|
||||
c.updated_at,
|
||||
c.parent_chat_id,
|
||||
c.root_chat_id,
|
||||
c.last_model_config_id,
|
||||
c.last_reasoning_effort,
|
||||
c.archived,
|
||||
c.last_error,
|
||||
c.mode,
|
||||
c.mcp_server_ids,
|
||||
c.labels,
|
||||
c.build_id,
|
||||
c.agent_id,
|
||||
c.pin_order,
|
||||
c.last_read_message_id,
|
||||
c.dynamic_tools,
|
||||
c.organization_id,
|
||||
c.plan_mode,
|
||||
c.client_type,
|
||||
c.last_turn_summary,
|
||||
c.snapshot_version,
|
||||
c.history_version,
|
||||
c.queue_version,
|
||||
c.generation_attempt,
|
||||
c.retry_state,
|
||||
c.retry_state_version,
|
||||
c.runner_id,
|
||||
c.requires_action_deadline_at,
|
||||
COALESCE(root.user_acl, c.user_acl) AS user_acl,
|
||||
COALESCE(root.group_acl, c.group_acl) AS group_acl,
|
||||
owner.username AS owner_username,
|
||||
owner.name AS owner_name,
|
||||
c.context_aggregate_hash,
|
||||
c.context_dirty_since,
|
||||
c.context_dirty_resources,
|
||||
c.context_error,
|
||||
c.compaction_requested_at
|
||||
FROM ((chats c
|
||||
LEFT JOIN chats root ON ((root.id = COALESCE(c.root_chat_id, c.parent_chat_id))))
|
||||
JOIN visible_users owner ON ((owner.id = c.owner_id)));
|
||||
@@ -0,0 +1,60 @@
|
||||
-- Persisted whole-chat summary and its freshness marker, distinct from
|
||||
-- last_turn_summary (which only reflects the most recent turn).
|
||||
ALTER TABLE chats
|
||||
ADD COLUMN summary TEXT,
|
||||
ADD COLUMN summary_generated_at TIMESTAMPTZ;
|
||||
|
||||
-- Recreate chats_expanded: its explicit column list hides new columns otherwise.
|
||||
DROP VIEW IF EXISTS chats_expanded;
|
||||
|
||||
CREATE VIEW chats_expanded AS
|
||||
SELECT c.id,
|
||||
c.owner_id,
|
||||
c.workspace_id,
|
||||
c.title,
|
||||
c.status,
|
||||
c.worker_id,
|
||||
c.started_at,
|
||||
c.heartbeat_at,
|
||||
c.created_at,
|
||||
c.updated_at,
|
||||
c.parent_chat_id,
|
||||
c.root_chat_id,
|
||||
c.last_model_config_id,
|
||||
c.last_reasoning_effort,
|
||||
c.archived,
|
||||
c.last_error,
|
||||
c.mode,
|
||||
c.mcp_server_ids,
|
||||
c.labels,
|
||||
c.build_id,
|
||||
c.agent_id,
|
||||
c.pin_order,
|
||||
c.last_read_message_id,
|
||||
c.dynamic_tools,
|
||||
c.organization_id,
|
||||
c.plan_mode,
|
||||
c.client_type,
|
||||
c.last_turn_summary,
|
||||
c.summary,
|
||||
c.summary_generated_at,
|
||||
c.snapshot_version,
|
||||
c.history_version,
|
||||
c.queue_version,
|
||||
c.generation_attempt,
|
||||
c.retry_state,
|
||||
c.retry_state_version,
|
||||
c.runner_id,
|
||||
c.requires_action_deadline_at,
|
||||
COALESCE(root.user_acl, c.user_acl) AS user_acl,
|
||||
COALESCE(root.group_acl, c.group_acl) AS group_acl,
|
||||
owner.username AS owner_username,
|
||||
owner.name AS owner_name,
|
||||
c.context_aggregate_hash,
|
||||
c.context_dirty_since,
|
||||
c.context_dirty_resources,
|
||||
c.context_error,
|
||||
c.compaction_requested_at
|
||||
FROM ((chats c
|
||||
LEFT JOIN chats root ON ((root.id = COALESCE(c.root_chat_id, c.parent_chat_id))))
|
||||
JOIN visible_users owner ON ((owner.id = c.owner_id)));
|
||||
@@ -826,6 +826,8 @@ func (q *sqlQuerier) GetAuthorizedChats(ctx context.Context, arg GetChatsParams,
|
||||
&i.Chat.PlanMode,
|
||||
&i.Chat.ClientType,
|
||||
&i.Chat.LastTurnSummary,
|
||||
&i.Chat.Summary,
|
||||
&i.Chat.SummaryGeneratedAt,
|
||||
&i.Chat.SnapshotVersion,
|
||||
&i.Chat.HistoryVersion,
|
||||
&i.Chat.QueueVersion,
|
||||
@@ -906,6 +908,8 @@ func (q *sqlQuerier) GetAuthorizedChatsByChatFileID(ctx context.Context, fileID
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
|
||||
Generated
+5
-1
@@ -4970,6 +4970,8 @@ type Chat struct {
|
||||
PlanMode NullChatPlanMode `db:"plan_mode" json:"plan_mode"`
|
||||
ClientType ChatClientType `db:"client_type" json:"client_type"`
|
||||
LastTurnSummary sql.NullString `db:"last_turn_summary" json:"last_turn_summary"`
|
||||
Summary sql.NullString `db:"summary" json:"summary"`
|
||||
SummaryGeneratedAt sql.NullTime `db:"summary_generated_at" json:"summary_generated_at"`
|
||||
SnapshotVersion int64 `db:"snapshot_version" json:"snapshot_version"`
|
||||
HistoryVersion int64 `db:"history_version" json:"history_version"`
|
||||
QueueVersion int64 `db:"queue_version" json:"queue_version"`
|
||||
@@ -5209,7 +5211,9 @@ type ChatTable struct {
|
||||
// Stores the most recent message effort once per-turn selection is wired.
|
||||
LastReasoningEffort NullChatReasoningEffort `db:"last_reasoning_effort" json:"last_reasoning_effort"`
|
||||
// Set when the chat owner manually requests a context compaction. One-shot signal: consumed by the compaction commit and cleared whenever the chat leaves running.
|
||||
CompactionRequestedAt sql.NullTime `db:"compaction_requested_at" json:"compaction_requested_at"`
|
||||
CompactionRequestedAt sql.NullTime `db:"compaction_requested_at" json:"compaction_requested_at"`
|
||||
Summary sql.NullString `db:"summary" json:"summary"`
|
||||
SummaryGeneratedAt sql.NullTime `db:"summary_generated_at" json:"summary_generated_at"`
|
||||
}
|
||||
|
||||
type ChatUsageLimitConfig struct {
|
||||
|
||||
Generated
+3
@@ -1426,6 +1426,9 @@ type sqlcQuerier interface {
|
||||
// assigned by trigger from the current snapshot_version.
|
||||
UpdateChatRetryState(ctx context.Context, arg UpdateChatRetryStateParams) (Chat, error)
|
||||
UpdateChatStatus(ctx context.Context, arg UpdateChatStatusParams) (Chat, error)
|
||||
// The history_version fence lets background summary writes ignore worker-only
|
||||
// updates while losing to newer message history.
|
||||
UpdateChatSummary(ctx context.Context, arg UpdateChatSummaryParams) (int64, error)
|
||||
UpdateChatTitleByID(ctx context.Context, arg UpdateChatTitleByIDParams) (Chat, error)
|
||||
UpdateChatWorkspaceBinding(ctx context.Context, arg UpdateChatWorkspaceBindingParams) (Chat, error)
|
||||
UpdateCryptoKeyDeletesAt(ctx context.Context, arg UpdateCryptoKeyDeletesAtParams) (CryptoKey, error)
|
||||
|
||||
@@ -14699,6 +14699,128 @@ func TestUpdateChatLastTurnSummary(t *testing.T) {
|
||||
require.NotEqual(t, chat.HistoryVersion, fetched.HistoryVersion)
|
||||
}
|
||||
|
||||
func TestUpdateChatSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
if testing.Short() {
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
sqlDB := testSQLDB(t)
|
||||
err := migrations.Up(sqlDB)
|
||||
require.NoError(t, err)
|
||||
db := database.New(sqlDB)
|
||||
|
||||
owner := dbgen.User(t, db, database.User{})
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
dbgen.OrganizationMember(t, db, database.OrganizationMember{UserID: owner.ID, OrganizationID: org.ID})
|
||||
|
||||
dbgen.ChatProvider(t, db, database.ChatProvider{
|
||||
Provider: "openai",
|
||||
DisplayName: "OpenAI",
|
||||
APIKey: "test-key",
|
||||
Enabled: true,
|
||||
CentralApiKeyEnabled: true,
|
||||
})
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
modelCfg, err := insertChatModelConfigForTest(ctx, t, db, "openai", database.InsertChatModelConfigParams{
|
||||
Model: "test-model",
|
||||
DisplayName: "Test Model",
|
||||
CreatedBy: uuid.NullUUID{UUID: owner.ID, Valid: true},
|
||||
UpdatedBy: uuid.NullUUID{UUID: owner.ID, Valid: true},
|
||||
Enabled: true,
|
||||
IsDefault: true,
|
||||
ContextLimit: 128000,
|
||||
CompressionThreshold: 80,
|
||||
Options: json.RawMessage(`{}`),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
chat, err := db.InsertChat(ctx, database.InsertChatParams{
|
||||
OrganizationID: org.ID,
|
||||
Status: database.ChatStatusWaiting,
|
||||
ClientType: database.ChatClientTypeUi,
|
||||
OwnerID: owner.ID,
|
||||
LastModelConfigID: modelCfg.ID,
|
||||
Title: "summary-chat",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.False(t, chat.Summary.Valid)
|
||||
require.False(t, chat.SummaryGeneratedAt.Valid)
|
||||
|
||||
affected, err := db.UpdateChatSummary(ctx, database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: chat.HistoryVersion,
|
||||
Summary: sql.NullString{String: "Implemented the whole-chat summary feature.", Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, affected)
|
||||
|
||||
fetched, err := db.GetChatByID(ctx, chat.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sql.NullString{String: "Implemented the whole-chat summary feature.", Valid: true}, fetched.Summary)
|
||||
require.True(t, fetched.SummaryGeneratedAt.Valid)
|
||||
require.Equal(t, chat.UpdatedAt, fetched.UpdatedAt)
|
||||
|
||||
affected, err = db.UpdateChatSummary(ctx, database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: chat.HistoryVersion,
|
||||
Summary: sql.NullString{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, affected)
|
||||
|
||||
fetched, err = db.GetChatByID(ctx, chat.ID)
|
||||
require.NoError(t, err)
|
||||
require.False(t, fetched.Summary.Valid)
|
||||
require.Equal(t, chat.UpdatedAt, fetched.UpdatedAt)
|
||||
|
||||
// Background summaries generated from stale history must lose to newer turns.
|
||||
affected, err = db.UpdateChatSummary(ctx, database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: chat.HistoryVersion,
|
||||
Summary: sql.NullString{String: "Fresh whole-chat summary.", Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1, affected)
|
||||
|
||||
_, err = db.LockChatAndBumpSnapshotVersion(ctx, chat.ID)
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertChatMessages(ctx, database.InsertChatMessagesParams{
|
||||
ChatID: chat.ID,
|
||||
CreatedBy: []uuid.UUID{owner.ID},
|
||||
ModelConfigID: []uuid.UUID{modelCfg.ID},
|
||||
Role: []database.ChatMessageRole{database.ChatMessageRoleUser},
|
||||
Content: []string{`[{"type":"text","text":"new request"}]`},
|
||||
ContentVersion: []int16{chatprompt.CurrentContentVersion},
|
||||
Visibility: []database.ChatMessageVisibility{database.ChatMessageVisibilityBoth},
|
||||
InputTokens: []int64{0},
|
||||
OutputTokens: []int64{0},
|
||||
TotalTokens: []int64{0},
|
||||
ReasoningTokens: []int64{0},
|
||||
CacheCreationTokens: []int64{0},
|
||||
CacheReadTokens: []int64{0},
|
||||
ContextLimit: []int64{0},
|
||||
Compressed: []bool{false},
|
||||
TotalCostMicros: []int64{0},
|
||||
RuntimeMs: []int64{0},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
affected, err = db.UpdateChatSummary(ctx, database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: chat.HistoryVersion,
|
||||
Summary: sql.NullString{String: "Stale whole-chat summary.", Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, affected)
|
||||
|
||||
fetched, err = db.GetChatByID(ctx, chat.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sql.NullString{String: "Fresh whole-chat summary.", Valid: true}, fetched.Summary)
|
||||
require.NotEqual(t, chat.HistoryVersion, fetched.HistoryVersion)
|
||||
}
|
||||
|
||||
func TestUpdateChatWorkspaceBindingNoOp(t *testing.T) {
|
||||
t.Parallel()
|
||||
if testing.Short() {
|
||||
|
||||
Generated
+171
-49
@@ -6050,7 +6050,7 @@ WITH updated_chats AS (
|
||||
UPDATE chats
|
||||
SET archived = true, pin_order = 0, updated_at = NOW()
|
||||
WHERE id = $1::uuid OR root_chat_id = $1::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -6082,6 +6082,8 @@ chats_expanded AS (
|
||||
updated_chats.plan_mode,
|
||||
updated_chats.client_type,
|
||||
updated_chats.last_turn_summary,
|
||||
updated_chats.summary,
|
||||
updated_chats.summary_generated_at,
|
||||
updated_chats.snapshot_version,
|
||||
updated_chats.history_version,
|
||||
updated_chats.queue_version,
|
||||
@@ -6104,7 +6106,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chats.root_chat_id, updated_chats.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chats.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
ORDER BY (chats_expanded.id = $1::uuid) DESC, chats_expanded.created_at ASC, chats_expanded.id ASC
|
||||
`
|
||||
@@ -6147,6 +6149,8 @@ func (q *sqlQuerier) ArchiveChatByID(ctx context.Context, id uuid.UUID) ([]Chat,
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -6214,10 +6218,10 @@ archived AS (
|
||||
FROM to_archive t
|
||||
WHERE (c.id = t.id OR c.root_chat_id = t.id) -- cascade to children
|
||||
AND c.archived = false
|
||||
RETURNING c.id, c.owner_id, c.workspace_id, c.title, c.status, c.worker_id, c.started_at, c.heartbeat_at, c.created_at, c.updated_at, c.parent_chat_id, c.root_chat_id, c.last_model_config_id, c.archived, c.last_error, c.mode, c.mcp_server_ids, c.labels, c.build_id, c.agent_id, c.pin_order, c.last_read_message_id, c.dynamic_tools, c.organization_id, c.plan_mode, c.client_type, c.last_turn_summary, c.user_acl, c.group_acl, c.snapshot_version, c.history_version, c.queue_version, c.generation_attempt, c.retry_state, c.retry_state_version, c.runner_id, c.requires_action_deadline_at, c.context_aggregate_hash, c.context_dirty_since, c.context_dirty_resources, c.context_error, c.last_reasoning_effort, c.compaction_requested_at
|
||||
RETURNING c.id, c.owner_id, c.workspace_id, c.title, c.status, c.worker_id, c.started_at, c.heartbeat_at, c.created_at, c.updated_at, c.parent_chat_id, c.root_chat_id, c.last_model_config_id, c.archived, c.last_error, c.mode, c.mcp_server_ids, c.labels, c.build_id, c.agent_id, c.pin_order, c.last_read_message_id, c.dynamic_tools, c.organization_id, c.plan_mode, c.client_type, c.last_turn_summary, c.user_acl, c.group_acl, c.snapshot_version, c.history_version, c.queue_version, c.generation_attempt, c.retry_state, c.retry_state_version, c.runner_id, c.requires_action_deadline_at, c.context_aggregate_hash, c.context_dirty_since, c.context_dirty_resources, c.context_error, c.last_reasoning_effort, c.compaction_requested_at, c.summary, c.summary_generated_at
|
||||
)
|
||||
SELECT
|
||||
a.id, a.owner_id, a.workspace_id, a.title, a.status, a.worker_id, a.started_at, a.heartbeat_at, a.created_at, a.updated_at, a.parent_chat_id, a.root_chat_id, a.last_model_config_id, a.archived, a.last_error, a.mode, a.mcp_server_ids, a.labels, a.build_id, a.agent_id, a.pin_order, a.last_read_message_id, a.dynamic_tools, a.organization_id, a.plan_mode, a.client_type, a.last_turn_summary, a.user_acl, a.group_acl, a.snapshot_version, a.history_version, a.queue_version, a.generation_attempt, a.retry_state, a.retry_state_version, a.runner_id, a.requires_action_deadline_at, a.context_aggregate_hash, a.context_dirty_since, a.context_dirty_resources, a.context_error, a.last_reasoning_effort, a.compaction_requested_at,
|
||||
a.id, a.owner_id, a.workspace_id, a.title, a.status, a.worker_id, a.started_at, a.heartbeat_at, a.created_at, a.updated_at, a.parent_chat_id, a.root_chat_id, a.last_model_config_id, a.archived, a.last_error, a.mode, a.mcp_server_ids, a.labels, a.build_id, a.agent_id, a.pin_order, a.last_read_message_id, a.dynamic_tools, a.organization_id, a.plan_mode, a.client_type, a.last_turn_summary, a.user_acl, a.group_acl, a.snapshot_version, a.history_version, a.queue_version, a.generation_attempt, a.retry_state, a.retry_state_version, a.runner_id, a.requires_action_deadline_at, a.context_aggregate_hash, a.context_dirty_since, a.context_dirty_resources, a.context_error, a.last_reasoning_effort, a.compaction_requested_at, a.summary, a.summary_generated_at,
|
||||
-- Children inherit their root's activity so last_activity_at is never null.
|
||||
COALESCE(
|
||||
t.last_activity_at,
|
||||
@@ -6278,6 +6282,8 @@ type AutoArchiveInactiveChatsRow struct {
|
||||
ContextError string `db:"context_error" json:"context_error"`
|
||||
LastReasoningEffort NullChatReasoningEffort `db:"last_reasoning_effort" json:"last_reasoning_effort"`
|
||||
CompactionRequestedAt sql.NullTime `db:"compaction_requested_at" json:"compaction_requested_at"`
|
||||
Summary sql.NullString `db:"summary" json:"summary"`
|
||||
SummaryGeneratedAt sql.NullTime `db:"summary_generated_at" json:"summary_generated_at"`
|
||||
LastActivityAt time.Time `db:"last_activity_at" json:"last_activity_at"`
|
||||
}
|
||||
|
||||
@@ -6341,6 +6347,8 @@ func (q *sqlQuerier) AutoArchiveInactiveChats(ctx context.Context, arg AutoArchi
|
||||
&i.ContextError,
|
||||
&i.LastReasoningEffort,
|
||||
&i.CompactionRequestedAt,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.LastActivityAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
@@ -6647,7 +6655,7 @@ func (q *sqlQuerier) DeleteStaleChatHeartbeats(ctx context.Context, staleSeconds
|
||||
}
|
||||
|
||||
const getActiveChatsByAgentID = `-- name: GetActiveChatsByAgentID :many
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
WHERE agent_id = $1::uuid
|
||||
AND archived = false
|
||||
@@ -6695,6 +6703,8 @@ func (q *sqlQuerier) GetActiveChatsByAgentID(ctx context.Context, agentID uuid.U
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -6728,7 +6738,7 @@ func (q *sqlQuerier) GetActiveChatsByAgentID(ctx context.Context, agentID uuid.U
|
||||
|
||||
const getAutoArchiveInactiveChatCandidates = `-- name: GetAutoArchiveInactiveChatCandidates :many
|
||||
SELECT
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.summary, chats_expanded.summary_generated_at, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
COALESCE(activity.last_activity_at, chats_expanded.created_at)::timestamptz AS last_activity_at
|
||||
FROM chats_expanded
|
||||
LEFT JOIN LATERAL (
|
||||
@@ -6787,6 +6797,8 @@ type GetAutoArchiveInactiveChatCandidatesRow struct {
|
||||
PlanMode NullChatPlanMode `db:"plan_mode" json:"plan_mode"`
|
||||
ClientType ChatClientType `db:"client_type" json:"client_type"`
|
||||
LastTurnSummary sql.NullString `db:"last_turn_summary" json:"last_turn_summary"`
|
||||
Summary sql.NullString `db:"summary" json:"summary"`
|
||||
SummaryGeneratedAt sql.NullTime `db:"summary_generated_at" json:"summary_generated_at"`
|
||||
SnapshotVersion int64 `db:"snapshot_version" json:"snapshot_version"`
|
||||
HistoryVersion int64 `db:"history_version" json:"history_version"`
|
||||
QueueVersion int64 `db:"queue_version" json:"queue_version"`
|
||||
@@ -6848,6 +6860,8 @@ func (q *sqlQuerier) GetAutoArchiveInactiveChatCandidates(ctx context.Context, a
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -6903,7 +6917,7 @@ func (q *sqlQuerier) GetChatACLByID(ctx context.Context, id uuid.UUID) (GetChatA
|
||||
}
|
||||
|
||||
const getChatByID = `-- name: GetChatByID :one
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
WHERE id = $1::uuid
|
||||
`
|
||||
@@ -6940,6 +6954,8 @@ func (q *sqlQuerier) GetChatByID(ctx context.Context, id uuid.UUID) (Chat, error
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -6963,7 +6979,7 @@ func (q *sqlQuerier) GetChatByID(ctx context.Context, id uuid.UUID) (Chat, error
|
||||
|
||||
const getChatByIDForShare = `-- name: GetChatByIDForShare :one
|
||||
WITH shared_chat AS (
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
FROM chats
|
||||
WHERE id = $1::uuid
|
||||
FOR SHARE
|
||||
@@ -6998,6 +7014,8 @@ chats_expanded AS (
|
||||
shared_chat.plan_mode,
|
||||
shared_chat.client_type,
|
||||
shared_chat.last_turn_summary,
|
||||
shared_chat.summary,
|
||||
shared_chat.summary_generated_at,
|
||||
shared_chat.snapshot_version,
|
||||
shared_chat.history_version,
|
||||
shared_chat.queue_version,
|
||||
@@ -7020,7 +7038,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(shared_chat.root_chat_id, shared_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = shared_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -7056,6 +7074,8 @@ func (q *sqlQuerier) GetChatByIDForShare(ctx context.Context, id uuid.UUID) (Cha
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -7079,7 +7099,7 @@ func (q *sqlQuerier) GetChatByIDForShare(ctx context.Context, id uuid.UUID) (Cha
|
||||
|
||||
const getChatByIDForUpdate = `-- name: GetChatByIDForUpdate :one
|
||||
WITH locked_chat AS (
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
FROM chats
|
||||
WHERE id = $1::uuid
|
||||
FOR UPDATE
|
||||
@@ -7114,6 +7134,8 @@ chats_expanded AS (
|
||||
locked_chat.plan_mode,
|
||||
locked_chat.client_type,
|
||||
locked_chat.last_turn_summary,
|
||||
locked_chat.summary,
|
||||
locked_chat.summary_generated_at,
|
||||
locked_chat.snapshot_version,
|
||||
locked_chat.history_version,
|
||||
locked_chat.queue_version,
|
||||
@@ -7136,7 +7158,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(locked_chat.root_chat_id, locked_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = locked_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -7172,6 +7194,8 @@ func (q *sqlQuerier) GetChatByIDForUpdate(ctx context.Context, id uuid.UUID) (Ch
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -8647,7 +8671,7 @@ func (q *sqlQuerier) GetChatUserPromptsByChatID(ctx context.Context, arg GetChat
|
||||
|
||||
const getChatWorkerAcquisitionCandidates = `-- name: GetChatWorkerAcquisitionCandidates :many
|
||||
SELECT
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.summary, chats_expanded.summary_generated_at, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
chat_heartbeats.heartbeat_at AS current_heartbeat_at,
|
||||
NOT EXISTS (
|
||||
SELECT 1
|
||||
@@ -8712,6 +8736,8 @@ type GetChatWorkerAcquisitionCandidatesRow struct {
|
||||
PlanMode NullChatPlanMode `db:"plan_mode" json:"plan_mode"`
|
||||
ClientType ChatClientType `db:"client_type" json:"client_type"`
|
||||
LastTurnSummary sql.NullString `db:"last_turn_summary" json:"last_turn_summary"`
|
||||
Summary sql.NullString `db:"summary" json:"summary"`
|
||||
SummaryGeneratedAt sql.NullTime `db:"summary_generated_at" json:"summary_generated_at"`
|
||||
SnapshotVersion int64 `db:"snapshot_version" json:"snapshot_version"`
|
||||
HistoryVersion int64 `db:"history_version" json:"history_version"`
|
||||
QueueVersion int64 `db:"queue_version" json:"queue_version"`
|
||||
@@ -8782,6 +8808,8 @@ func (q *sqlQuerier) GetChatWorkerAcquisitionCandidates(ctx context.Context, arg
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -8825,7 +8853,7 @@ WITH cursor_chat AS (
|
||||
WHERE id = $7
|
||||
)
|
||||
SELECT
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.summary, chats_expanded.summary_generated_at, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
EXISTS (
|
||||
SELECT 1 FROM chat_messages cm
|
||||
WHERE cm.chat_id = chats_expanded.id
|
||||
@@ -9107,6 +9135,8 @@ func (q *sqlQuerier) GetChats(ctx context.Context, arg GetChatsParams) ([]GetCha
|
||||
&i.Chat.PlanMode,
|
||||
&i.Chat.ClientType,
|
||||
&i.Chat.LastTurnSummary,
|
||||
&i.Chat.Summary,
|
||||
&i.Chat.SummaryGeneratedAt,
|
||||
&i.Chat.SnapshotVersion,
|
||||
&i.Chat.HistoryVersion,
|
||||
&i.Chat.QueueVersion,
|
||||
@@ -9141,7 +9171,7 @@ func (q *sqlQuerier) GetChats(ctx context.Context, arg GetChatsParams) ([]GetCha
|
||||
|
||||
const getChatsByChatFileID = `-- name: GetChatsByChatFileID :many
|
||||
SELECT
|
||||
id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM
|
||||
chats_expanded
|
||||
WHERE
|
||||
@@ -9192,6 +9222,8 @@ func (q *sqlQuerier) GetChatsByChatFileID(ctx context.Context, fileID uuid.UUID)
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -9224,7 +9256,7 @@ func (q *sqlQuerier) GetChatsByChatFileID(ctx context.Context, fileID uuid.UUID)
|
||||
}
|
||||
|
||||
const getChatsByIDsForRunnerSync = `-- name: GetChatsByIDsForRunnerSync :many
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
WHERE id = ANY($1::uuid[])
|
||||
ORDER BY id ASC
|
||||
@@ -9268,6 +9300,8 @@ func (q *sqlQuerier) GetChatsByIDsForRunnerSync(ctx context.Context, ids []uuid.
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -9300,7 +9334,7 @@ func (q *sqlQuerier) GetChatsByIDsForRunnerSync(ctx context.Context, ids []uuid.
|
||||
}
|
||||
|
||||
const getChatsByWorkspaceIDs = `-- name: GetChatsByWorkspaceIDs :many
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
WHERE archived = false
|
||||
AND workspace_id = ANY($1::uuid[])
|
||||
@@ -9345,6 +9379,8 @@ func (q *sqlQuerier) GetChatsByWorkspaceIDs(ctx context.Context, ids []uuid.UUID
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -9446,7 +9482,7 @@ func (q *sqlQuerier) GetChatsUpdatedAfter(ctx context.Context, updatedAfter time
|
||||
|
||||
const getChildChatsByParentIDs = `-- name: GetChildChatsByParentIDs :many
|
||||
SELECT
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
chats_expanded.id, chats_expanded.owner_id, chats_expanded.workspace_id, chats_expanded.title, chats_expanded.status, chats_expanded.worker_id, chats_expanded.started_at, chats_expanded.heartbeat_at, chats_expanded.created_at, chats_expanded.updated_at, chats_expanded.parent_chat_id, chats_expanded.root_chat_id, chats_expanded.last_model_config_id, chats_expanded.last_reasoning_effort, chats_expanded.archived, chats_expanded.last_error, chats_expanded.mode, chats_expanded.mcp_server_ids, chats_expanded.labels, chats_expanded.build_id, chats_expanded.agent_id, chats_expanded.pin_order, chats_expanded.last_read_message_id, chats_expanded.dynamic_tools, chats_expanded.organization_id, chats_expanded.plan_mode, chats_expanded.client_type, chats_expanded.last_turn_summary, chats_expanded.summary, chats_expanded.summary_generated_at, chats_expanded.snapshot_version, chats_expanded.history_version, chats_expanded.queue_version, chats_expanded.generation_attempt, chats_expanded.retry_state, chats_expanded.retry_state_version, chats_expanded.runner_id, chats_expanded.requires_action_deadline_at, chats_expanded.user_acl, chats_expanded.group_acl, chats_expanded.owner_username, chats_expanded.owner_name, chats_expanded.context_aggregate_hash, chats_expanded.context_dirty_since, chats_expanded.context_dirty_resources, chats_expanded.context_error, chats_expanded.compaction_requested_at,
|
||||
EXISTS (
|
||||
SELECT 1 FROM chat_messages cm
|
||||
WHERE cm.chat_id = chats_expanded.id
|
||||
@@ -9519,6 +9555,8 @@ func (q *sqlQuerier) GetChildChatsByParentIDs(ctx context.Context, arg GetChildC
|
||||
&i.Chat.PlanMode,
|
||||
&i.Chat.ClientType,
|
||||
&i.Chat.LastTurnSummary,
|
||||
&i.Chat.Summary,
|
||||
&i.Chat.SummaryGeneratedAt,
|
||||
&i.Chat.SnapshotVersion,
|
||||
&i.Chat.HistoryVersion,
|
||||
&i.Chat.QueueVersion,
|
||||
@@ -9619,7 +9657,7 @@ func (q *sqlQuerier) GetLastChatMessageByRole(ctx context.Context, arg GetLastCh
|
||||
|
||||
const getStaleChats = `-- name: GetStaleChats :many
|
||||
SELECT
|
||||
id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM
|
||||
chats_expanded
|
||||
WHERE
|
||||
@@ -9680,6 +9718,8 @@ func (q *sqlQuerier) GetStaleChats(ctx context.Context, staleThreshold time.Time
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -9925,7 +9965,7 @@ INSERT INTO chats (
|
||||
$15::jsonb,
|
||||
$16::chat_client_type
|
||||
)
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -9957,6 +9997,8 @@ chats_expanded AS (
|
||||
inserted_chat.plan_mode,
|
||||
inserted_chat.client_type,
|
||||
inserted_chat.last_turn_summary,
|
||||
inserted_chat.summary,
|
||||
inserted_chat.summary_generated_at,
|
||||
inserted_chat.snapshot_version,
|
||||
inserted_chat.history_version,
|
||||
inserted_chat.queue_version,
|
||||
@@ -9979,7 +10021,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(inserted_chat.root_chat_id, inserted_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = inserted_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -10051,6 +10093,8 @@ func (q *sqlQuerier) InsertChat(ctx context.Context, arg InsertChatParams) (Chat
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -10555,7 +10599,7 @@ WITH bumped_chat AS (
|
||||
WHERE id = $1::uuid
|
||||
FOR UPDATE
|
||||
)
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -10587,6 +10631,8 @@ chats_expanded AS (
|
||||
bumped_chat.plan_mode,
|
||||
bumped_chat.client_type,
|
||||
bumped_chat.last_turn_summary,
|
||||
bumped_chat.summary,
|
||||
bumped_chat.summary_generated_at,
|
||||
bumped_chat.snapshot_version,
|
||||
bumped_chat.history_version,
|
||||
bumped_chat.queue_version,
|
||||
@@ -10608,7 +10654,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(bumped_chat.root_chat_id, bumped_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = bumped_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -10648,6 +10694,8 @@ func (q *sqlQuerier) LockChatAndBumpSnapshotVersion(ctx context.Context, id uuid
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -10995,7 +11043,7 @@ WITH updated_chats AS (
|
||||
archived = false,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1::uuid OR root_chat_id = $1::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -11027,6 +11075,8 @@ chats_expanded AS (
|
||||
updated_chats.plan_mode,
|
||||
updated_chats.client_type,
|
||||
updated_chats.last_turn_summary,
|
||||
updated_chats.summary,
|
||||
updated_chats.summary_generated_at,
|
||||
updated_chats.snapshot_version,
|
||||
updated_chats.history_version,
|
||||
updated_chats.queue_version,
|
||||
@@ -11049,7 +11099,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chats.root_chat_id, updated_chats.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chats.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
ORDER BY (chats_expanded.id = $1::uuid) DESC, chats_expanded.created_at ASC, chats_expanded.id ASC
|
||||
`
|
||||
@@ -11096,6 +11146,8 @@ func (q *sqlQuerier) UnarchiveChatByID(ctx context.Context, id uuid.UUID) ([]Cha
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -11215,7 +11267,7 @@ UPDATE chats SET
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
id = $3::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -11247,6 +11299,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -11269,7 +11323,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -11311,6 +11365,8 @@ func (q *sqlQuerier) UpdateChatBuildAgentBinding(ctx context.Context, arg Update
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -11341,7 +11397,7 @@ SET
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
id = $2::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -11373,6 +11429,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -11395,7 +11453,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -11436,6 +11494,8 @@ func (q *sqlQuerier) UpdateChatByID(ctx context.Context, arg UpdateChatByIDParam
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -11471,7 +11531,7 @@ WITH updated_chat AS (
|
||||
pin_order = CASE WHEN $2::boolean THEN 0 ELSE pin_order END,
|
||||
updated_at = NOW()
|
||||
WHERE id = $8::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -11503,6 +11563,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -11524,7 +11586,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -11585,6 +11647,8 @@ func (q *sqlQuerier) UpdateChatExecutionState(ctx context.Context, arg UpdateCha
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -11660,7 +11724,7 @@ SET
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
id = $2::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -11692,6 +11756,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -11714,7 +11780,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -11755,6 +11821,8 @@ func (q *sqlQuerier) UpdateChatLabelsByID(ctx context.Context, arg UpdateChatLab
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -11785,7 +11853,7 @@ SET
|
||||
last_model_config_id = $1::uuid
|
||||
WHERE
|
||||
id = $2::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -11817,6 +11885,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -11839,7 +11909,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -11880,6 +11950,8 @@ func (q *sqlQuerier) UpdateChatLastModelConfigByID(ctx context.Context, arg Upda
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -11960,7 +12032,7 @@ SET
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
id = $2::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -11992,6 +12064,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -12014,7 +12088,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -12055,6 +12129,8 @@ func (q *sqlQuerier) UpdateChatMCPServerIDs(ctx context.Context, arg UpdateChatM
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -12156,7 +12232,7 @@ SET
|
||||
plan_mode = $1::chat_plan_mode
|
||||
WHERE
|
||||
id = $2::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -12188,6 +12264,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -12210,7 +12288,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -12251,6 +12329,8 @@ func (q *sqlQuerier) UpdateChatPlanModeByID(ctx context.Context, arg UpdateChatP
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -12279,7 +12359,7 @@ WITH updated_chat AS (
|
||||
retry_state = $1::jsonb,
|
||||
updated_at = NOW()
|
||||
WHERE id = $2::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -12311,6 +12391,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -12332,7 +12414,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -12375,6 +12457,8 @@ func (q *sqlQuerier) UpdateChatRetryState(ctx context.Context, arg UpdateChatRet
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -12409,7 +12493,7 @@ SET
|
||||
updated_at = NOW()
|
||||
WHERE
|
||||
id = $6::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -12441,6 +12525,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -12463,7 +12549,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -12515,6 +12601,8 @@ func (q *sqlQuerier) UpdateChatStatus(ctx context.Context, arg UpdateChatStatusP
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -12536,6 +12624,32 @@ func (q *sqlQuerier) UpdateChatStatus(ctx context.Context, arg UpdateChatStatusP
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateChatSummary = `-- name: UpdateChatSummary :execrows
|
||||
UPDATE chats
|
||||
SET
|
||||
summary = $1::text,
|
||||
summary_generated_at = NOW()
|
||||
WHERE
|
||||
id = $2::uuid
|
||||
AND history_version = $3::bigint
|
||||
`
|
||||
|
||||
type UpdateChatSummaryParams struct {
|
||||
Summary sql.NullString `db:"summary" json:"summary"`
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
ExpectedHistoryVersion int64 `db:"expected_history_version" json:"expected_history_version"`
|
||||
}
|
||||
|
||||
// The history_version fence lets background summary writes ignore worker-only
|
||||
// updates while losing to newer message history.
|
||||
func (q *sqlQuerier) UpdateChatSummary(ctx context.Context, arg UpdateChatSummaryParams) (int64, error) {
|
||||
result, err := q.db.ExecContext(ctx, updateChatSummary, arg.Summary, arg.ID, arg.ExpectedHistoryVersion)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
}
|
||||
|
||||
const updateChatTitleByID = `-- name: UpdateChatTitleByID :one
|
||||
WITH updated_chat AS (
|
||||
UPDATE
|
||||
@@ -12547,7 +12661,7 @@ SET
|
||||
title = $1::text
|
||||
WHERE
|
||||
id = $2::uuid
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
chats_expanded AS (
|
||||
SELECT
|
||||
@@ -12579,6 +12693,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -12601,7 +12717,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(updated_chat.root_chat_id, updated_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = updated_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -12642,6 +12758,8 @@ func (q *sqlQuerier) UpdateChatTitleByID(ctx context.Context, arg UpdateChatTitl
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
@@ -12665,7 +12783,7 @@ func (q *sqlQuerier) UpdateChatTitleByID(ctx context.Context, arg UpdateChatTitl
|
||||
|
||||
const updateChatWorkspaceBinding = `-- name: UpdateChatWorkspaceBinding :one
|
||||
WITH current_chat AS (
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
FROM chats
|
||||
WHERE id = $1::uuid
|
||||
),
|
||||
@@ -12684,13 +12802,13 @@ changed_chat AS (
|
||||
updated_at = NOW()
|
||||
WHERE id = $1::uuid
|
||||
AND (SELECT changed FROM binding_changed)
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
RETURNING id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
),
|
||||
result_chat AS (
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
FROM changed_chat
|
||||
UNION ALL
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, user_acl, group_acl, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, last_reasoning_effort, compaction_requested_at, summary, summary_generated_at
|
||||
FROM current_chat
|
||||
WHERE NOT (SELECT changed FROM binding_changed)
|
||||
),
|
||||
@@ -12724,6 +12842,8 @@ chats_expanded AS (
|
||||
result_chat.plan_mode,
|
||||
result_chat.client_type,
|
||||
result_chat.last_turn_summary,
|
||||
result_chat.summary,
|
||||
result_chat.summary_generated_at,
|
||||
result_chat.snapshot_version,
|
||||
result_chat.history_version,
|
||||
result_chat.queue_version,
|
||||
@@ -12746,7 +12866,7 @@ chats_expanded AS (
|
||||
LEFT JOIN chats root ON root.id = COALESCE(result_chat.root_chat_id, result_chat.parent_chat_id)
|
||||
JOIN visible_users owner ON owner.id = result_chat.owner_id
|
||||
)
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
SELECT id, owner_id, workspace_id, title, status, worker_id, started_at, heartbeat_at, created_at, updated_at, parent_chat_id, root_chat_id, last_model_config_id, last_reasoning_effort, archived, last_error, mode, mcp_server_ids, labels, build_id, agent_id, pin_order, last_read_message_id, dynamic_tools, organization_id, plan_mode, client_type, last_turn_summary, summary, summary_generated_at, snapshot_version, history_version, queue_version, generation_attempt, retry_state, retry_state_version, runner_id, requires_action_deadline_at, user_acl, group_acl, owner_username, owner_name, context_aggregate_hash, context_dirty_since, context_dirty_resources, context_error, compaction_requested_at
|
||||
FROM chats_expanded
|
||||
`
|
||||
|
||||
@@ -12794,6 +12914,8 @@ func (q *sqlQuerier) UpdateChatWorkspaceBinding(ctx context.Context, arg UpdateC
|
||||
&i.PlanMode,
|
||||
&i.ClientType,
|
||||
&i.LastTurnSummary,
|
||||
&i.Summary,
|
||||
&i.SummaryGeneratedAt,
|
||||
&i.SnapshotVersion,
|
||||
&i.HistoryVersion,
|
||||
&i.QueueVersion,
|
||||
|
||||
@@ -35,6 +35,8 @@ chats_expanded AS (
|
||||
updated_chats.plan_mode,
|
||||
updated_chats.client_type,
|
||||
updated_chats.last_turn_summary,
|
||||
updated_chats.summary,
|
||||
updated_chats.summary_generated_at,
|
||||
updated_chats.snapshot_version,
|
||||
updated_chats.history_version,
|
||||
updated_chats.queue_version,
|
||||
@@ -103,6 +105,8 @@ chats_expanded AS (
|
||||
updated_chats.plan_mode,
|
||||
updated_chats.client_type,
|
||||
updated_chats.last_turn_summary,
|
||||
updated_chats.summary,
|
||||
updated_chats.summary_generated_at,
|
||||
updated_chats.snapshot_version,
|
||||
updated_chats.history_version,
|
||||
updated_chats.queue_version,
|
||||
@@ -836,6 +840,8 @@ chats_expanded AS (
|
||||
inserted_chat.plan_mode,
|
||||
inserted_chat.client_type,
|
||||
inserted_chat.last_turn_summary,
|
||||
inserted_chat.summary,
|
||||
inserted_chat.summary_generated_at,
|
||||
inserted_chat.snapshot_version,
|
||||
inserted_chat.history_version,
|
||||
inserted_chat.queue_version,
|
||||
@@ -978,6 +984,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1046,6 +1054,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1112,6 +1122,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1178,6 +1190,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1244,6 +1258,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1330,6 +1346,8 @@ chats_expanded AS (
|
||||
result_chat.plan_mode,
|
||||
result_chat.client_type,
|
||||
result_chat.last_turn_summary,
|
||||
result_chat.summary,
|
||||
result_chat.summary_generated_at,
|
||||
result_chat.snapshot_version,
|
||||
result_chat.history_version,
|
||||
result_chat.queue_version,
|
||||
@@ -1395,6 +1413,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1437,6 +1457,17 @@ WHERE
|
||||
id = @id::uuid
|
||||
AND history_version = @expected_history_version::bigint;
|
||||
|
||||
-- name: UpdateChatSummary :execrows
|
||||
-- The history_version fence lets background summary writes ignore worker-only
|
||||
-- updates while losing to newer message history.
|
||||
UPDATE chats
|
||||
SET
|
||||
summary = sqlc.narg('summary')::text,
|
||||
summary_generated_at = NOW()
|
||||
WHERE
|
||||
id = @id::uuid
|
||||
AND history_version = @expected_history_version::bigint;
|
||||
|
||||
-- name: UpdateChatMCPServerIDs :one
|
||||
WITH updated_chat AS (
|
||||
UPDATE
|
||||
@@ -1478,6 +1509,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1686,6 +1719,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -1963,6 +1998,8 @@ chats_expanded AS (
|
||||
locked_chat.plan_mode,
|
||||
locked_chat.client_type,
|
||||
locked_chat.last_turn_summary,
|
||||
locked_chat.summary,
|
||||
locked_chat.summary_generated_at,
|
||||
locked_chat.snapshot_version,
|
||||
locked_chat.history_version,
|
||||
locked_chat.queue_version,
|
||||
@@ -2025,6 +2062,8 @@ chats_expanded AS (
|
||||
shared_chat.plan_mode,
|
||||
shared_chat.client_type,
|
||||
shared_chat.last_turn_summary,
|
||||
shared_chat.summary,
|
||||
shared_chat.summary_generated_at,
|
||||
shared_chat.snapshot_version,
|
||||
shared_chat.history_version,
|
||||
shared_chat.queue_version,
|
||||
@@ -2700,6 +2739,8 @@ chats_expanded AS (
|
||||
bumped_chat.plan_mode,
|
||||
bumped_chat.client_type,
|
||||
bumped_chat.last_turn_summary,
|
||||
bumped_chat.summary,
|
||||
bumped_chat.summary_generated_at,
|
||||
bumped_chat.snapshot_version,
|
||||
bumped_chat.history_version,
|
||||
bumped_chat.queue_version,
|
||||
@@ -2775,6 +2816,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
@@ -2840,6 +2883,8 @@ chats_expanded AS (
|
||||
updated_chat.plan_mode,
|
||||
updated_chat.client_type,
|
||||
updated_chat.last_turn_summary,
|
||||
updated_chat.summary,
|
||||
updated_chat.summary_generated_at,
|
||||
updated_chat.snapshot_version,
|
||||
updated_chat.history_version,
|
||||
updated_chat.queue_version,
|
||||
|
||||
@@ -4387,6 +4387,7 @@ func (p *Server) maybeFinalizeTurnStatusLabelAndPush(
|
||||
switch status {
|
||||
case database.ChatStatusWaiting:
|
||||
p.finalizeSuccessfulTurnStatusLabelAndPush(ctx, chat, status, runResult, logger)
|
||||
p.maybeGenerateChatSummaryAsync(ctx, logger, chat)
|
||||
|
||||
case database.ChatStatusError:
|
||||
p.clearLastTurnSummaryAsync(ctx, chat, logger)
|
||||
@@ -4614,6 +4615,200 @@ func (p *Server) updateLastTurnSummary(
|
||||
p.publishChatPubsubEvent(updatedChat, codersdk.ChatWatchEventKindSummaryChange, nil)
|
||||
}
|
||||
|
||||
const (
|
||||
// Completed user turns before the first summary is generated.
|
||||
summaryInitialTurnThreshold = 1
|
||||
// New completed user turns before the summary is regenerated (since the last summary).
|
||||
summaryStaleTurnThreshold = 3
|
||||
summaryMinTranscriptRunes = 200
|
||||
chatSummaryWorkTimeout = 120 * time.Second
|
||||
chatSummaryGenerateTimeout = 60 * time.Second
|
||||
chatSummaryWriteTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// maybeGenerateChatSummaryAsync launches best-effort whole-chat summary
|
||||
// generation in the background for a root chat.
|
||||
func (p *Server) maybeGenerateChatSummaryAsync(
|
||||
ctx context.Context,
|
||||
logger slog.Logger,
|
||||
chat database.Chat,
|
||||
) {
|
||||
if chat.ParentChatID.Valid {
|
||||
return
|
||||
}
|
||||
ctx, cancel := p.inflightContext(ctx)
|
||||
if err := p.goInflight(func() {
|
||||
defer cancel()
|
||||
p.generateAndStoreChatSummary(ctx, logger, chat)
|
||||
}); err != nil {
|
||||
cancel()
|
||||
logger.Debug(ctx, "skipped chat summary generation",
|
||||
slog.F("chat_id", chat.ID), slog.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// generateAndStoreChatSummary regenerates and persists the whole-chat summary
|
||||
// when due. Best-effort; never clears an existing summary on failure.
|
||||
func (p *Server) generateAndStoreChatSummary(
|
||||
ctx context.Context,
|
||||
logger slog.Logger,
|
||||
chat database.Chat,
|
||||
) {
|
||||
ctx, cancel := context.WithTimeout(ctx, chatSummaryWorkTimeout)
|
||||
defer cancel()
|
||||
|
||||
//nolint:gocritic // Narrow daemon access for best-effort summary generation.
|
||||
ctx = dbauthz.AsChatd(ctx)
|
||||
|
||||
// If a turn commits after this read, the stale history_version makes the
|
||||
// eventual summary write lose instead of omitting that newer turn.
|
||||
chat, err := p.db.GetChatByID(ctx, chat.ID)
|
||||
if err != nil {
|
||||
logger.Debug(ctx, "failed to re-read chat for summary",
|
||||
slog.F("chat_id", chat.ID), slog.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
messages, err := p.db.GetChatMessagesForPromptByChatID(ctx, chat.ID)
|
||||
if err != nil {
|
||||
logger.Debug(ctx, "failed to load messages for chat summary",
|
||||
slog.F("chat_id", chat.ID), slog.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
if !shouldGenerateChatSummary(chat, messages) {
|
||||
return
|
||||
}
|
||||
|
||||
transcript := renderChatSummaryTranscript(messages)
|
||||
if len([]rune(transcript)) < summaryMinTranscriptRunes {
|
||||
logger.Debug(ctx, "skipping chat summary for short transcript",
|
||||
slog.F("chat_id", chat.ID),
|
||||
slog.F("transcript_runes", len([]rune(transcript))),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Derive the delegated API key from the chat owner so AI Gateway routing
|
||||
// attributes summary generation to the correct account. This goroutine may
|
||||
// outlive the launching turn, so it cannot rely on that turn's context.
|
||||
apiKeyID, err := p.ensureSyntheticAPIKeyID(ctx, chat.OwnerID)
|
||||
if err != nil {
|
||||
logger.Debug(ctx, "failed to ensure synthetic API key for chat summary",
|
||||
slog.F("chat_id", chat.ID), slog.Error(err))
|
||||
return
|
||||
}
|
||||
modelOpts := modelBuildOptions{ActiveAPIKeyID: apiKeyID}
|
||||
|
||||
model, _, ok := p.resolveChatSummaryModel(ctx, logger, chat, modelOpts)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
summaryCtx, cancelGen := context.WithTimeout(ctx, chatSummaryGenerateTimeout)
|
||||
defer cancelGen()
|
||||
summary, _, genErr := generateChatSummary(summaryCtx, model, transcript)
|
||||
|
||||
if genErr != nil {
|
||||
logger.Debug(ctx, "failed to generate chat summary",
|
||||
slog.F("chat_id", chat.ID), slog.Error(genErr))
|
||||
return
|
||||
}
|
||||
|
||||
p.updateChatSummary(ctx, logger, chat, chat.HistoryVersion, summary)
|
||||
}
|
||||
|
||||
func (p *Server) resolveChatSummaryModel(
|
||||
ctx context.Context,
|
||||
logger slog.Logger,
|
||||
chat database.Chat,
|
||||
modelOpts modelBuildOptions,
|
||||
) (fantasy.LanguageModel, database.ChatModelConfig, bool) {
|
||||
//nolint:dogsled // resolveChatModel returns rich routing metadata; summary generation only needs the model and its config.
|
||||
model, dbConfig, _, _, _, _, err := p.resolveChatModel(ctx, chat, modelOpts)
|
||||
if err != nil {
|
||||
logger.Debug(ctx, "failed to resolve chat model for summary",
|
||||
slog.F("chat_id", chat.ID), slog.Error(err))
|
||||
return nil, database.ChatModelConfig{}, false
|
||||
}
|
||||
return model, dbConfig, true
|
||||
}
|
||||
|
||||
func shouldGenerateChatSummary(chat database.Chat, messages []database.ChatMessage) bool {
|
||||
if !chat.Summary.Valid {
|
||||
return countCompletedTurnsSince(messages, time.Time{}) >= summaryInitialTurnThreshold
|
||||
}
|
||||
var marker time.Time
|
||||
if chat.SummaryGeneratedAt.Valid {
|
||||
marker = chat.SummaryGeneratedAt.Time
|
||||
}
|
||||
return countCompletedTurnsSince(messages, marker) >= summaryStaleTurnThreshold
|
||||
}
|
||||
|
||||
// countCompletedTurnsSince counts visible user messages (one per turn) created
|
||||
// after the given time. Model-only user messages (injected context, replayed
|
||||
// compaction summary) are not turns; a zero time counts all.
|
||||
func countCompletedTurnsSince(messages []database.ChatMessage, after time.Time) int {
|
||||
count := 0
|
||||
for _, message := range messages {
|
||||
if message.Role != database.ChatMessageRoleUser {
|
||||
continue
|
||||
}
|
||||
if message.Visibility != database.ChatMessageVisibilityBoth &&
|
||||
message.Visibility != database.ChatMessageVisibilityUser {
|
||||
continue
|
||||
}
|
||||
if !after.IsZero() && !message.CreatedAt.After(after) {
|
||||
continue
|
||||
}
|
||||
count++
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// updateChatSummary persists the whole-chat summary. Best-effort background
|
||||
// write (pass a detached context); a blank summary is a no-op, never clearing
|
||||
// an existing one.
|
||||
func (p *Server) updateChatSummary(
|
||||
ctx context.Context,
|
||||
logger slog.Logger,
|
||||
chat database.Chat,
|
||||
expectedHistoryVersion int64,
|
||||
summary string,
|
||||
) {
|
||||
summary = strings.TrimSpace(summary)
|
||||
if summary == "" {
|
||||
return
|
||||
}
|
||||
sqlSummary := sql.NullString{String: summary, Valid: true}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, chatSummaryWriteTimeout)
|
||||
defer cancel()
|
||||
|
||||
affected, err := p.db.UpdateChatSummary(ctx, database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: expectedHistoryVersion,
|
||||
Summary: sqlSummary,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warn(ctx, "failed to update chat summary",
|
||||
slog.F("chat_id", chat.ID), slog.Error(err))
|
||||
return
|
||||
}
|
||||
if affected == 0 {
|
||||
logger.Info(ctx, "skipped stale chat summary update",
|
||||
slog.F("chat_id", chat.ID),
|
||||
slog.F("summary_length", len(summary)),
|
||||
slog.F("expected_history_version", expectedHistoryVersion),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
updatedChat := chat
|
||||
updatedChat.Summary = sqlSummary
|
||||
p.publishChatPubsubEvent(updatedChat, codersdk.ChatWatchEventKindChatSummaryChange, nil)
|
||||
}
|
||||
|
||||
func (p *Server) webpushConfigured() bool {
|
||||
return p.webpushDispatcher != nil && p.webpushDispatcher.PublicKey() != ""
|
||||
}
|
||||
|
||||
@@ -87,6 +87,115 @@ func (t *testMCPAgentTool) MCPServerConfigID() uuid.UUID {
|
||||
return t.configID
|
||||
}
|
||||
|
||||
func TestUpdateChatSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("TrimsAndPublishes", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
db := dbmock.NewMockStore(ctrl)
|
||||
ps := newRecordingPubsub(dbpubsub.NewInMemory())
|
||||
server := &Server{db: db, pubsub: ps}
|
||||
chat := database.Chat{ID: uuid.New(), OwnerID: uuid.New(), HistoryVersion: 7}
|
||||
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
|
||||
caller := rbac.Subject{
|
||||
ID: chat.OwnerID.String(),
|
||||
Type: rbac.SubjectTypeUser,
|
||||
Roles: rbac.RoleIdentifiers{rbac.RoleMember()},
|
||||
}
|
||||
//nolint:gocritic // Verify updateChatSummary preserves its caller's actor.
|
||||
ctx := dbauthz.As(context.Background(), caller)
|
||||
|
||||
db.EXPECT().UpdateChatSummary(gomock.Any(), database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: chat.HistoryVersion,
|
||||
Summary: sql.NullString{String: "trimmed summary", Valid: true},
|
||||
}).DoAndReturn(func(ctx context.Context, _ database.UpdateChatSummaryParams) (int64, error) {
|
||||
actor, ok := dbauthz.ActorFromContext(ctx)
|
||||
require.True(t, ok, "summary writes must preserve the caller's actor")
|
||||
require.Equal(t, caller, actor)
|
||||
return 1, nil
|
||||
})
|
||||
|
||||
server.updateChatSummary(ctx, logger, chat, chat.HistoryVersion, " \n trimmed summary\t ")
|
||||
|
||||
events := ps.watchEvents(t)
|
||||
require.Len(t, events, 1)
|
||||
require.Equal(t, codersdk.ChatWatchEventKindChatSummaryChange, events[0].Kind)
|
||||
require.NotNil(t, events[0].Chat.Summary)
|
||||
require.Equal(t, "trimmed summary", *events[0].Chat.Summary)
|
||||
})
|
||||
|
||||
t.Run("SkipsBlankSummary", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
db := dbmock.NewMockStore(ctrl)
|
||||
server := &Server{db: db}
|
||||
chat := database.Chat{ID: uuid.New(), OwnerID: uuid.New(), HistoryVersion: 7}
|
||||
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
|
||||
|
||||
server.updateChatSummary(context.Background(), logger, chat, chat.HistoryVersion, " \n\t ")
|
||||
})
|
||||
|
||||
t.Run("SkipsEventOnStaleWrite", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
db := dbmock.NewMockStore(ctrl)
|
||||
ps := newRecordingPubsub(dbpubsub.NewInMemory())
|
||||
server := &Server{db: db, pubsub: ps}
|
||||
chat := database.Chat{ID: uuid.New(), OwnerID: uuid.New(), HistoryVersion: 7}
|
||||
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
|
||||
|
||||
db.EXPECT().UpdateChatSummary(gomock.Any(), database.UpdateChatSummaryParams{
|
||||
ID: chat.ID,
|
||||
ExpectedHistoryVersion: chat.HistoryVersion,
|
||||
Summary: sql.NullString{String: "stale summary", Valid: true},
|
||||
}).Return(int64(0), nil)
|
||||
|
||||
server.updateChatSummary(context.Background(), logger, chat, chat.HistoryVersion, "stale summary")
|
||||
|
||||
require.Empty(t, ps.watchEvents(t))
|
||||
})
|
||||
}
|
||||
|
||||
func TestMaybeGenerateChatSummaryAsync_CloseCancelsInflight(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
db := dbmock.NewMockStore(ctrl)
|
||||
serverCtx, serverCancel := context.WithCancel(context.Background())
|
||||
t.Cleanup(serverCancel)
|
||||
server := &Server{ctx: serverCtx, cancel: serverCancel, db: db}
|
||||
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
|
||||
chat := database.Chat{ID: uuid.New(), OwnerID: uuid.New()}
|
||||
entered := make(chan struct{})
|
||||
db.EXPECT().GetChatByID(gomock.Any(), chat.ID).DoAndReturn(
|
||||
func(readCtx context.Context, _ uuid.UUID) (database.Chat, error) {
|
||||
close(entered)
|
||||
// Hang like an unreachable callee until the context is
|
||||
// canceled; only server shutdown can release this before
|
||||
// chatSummaryWorkTimeout.
|
||||
<-readCtx.Done()
|
||||
return database.Chat{}, readCtx.Err()
|
||||
},
|
||||
)
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
server.maybeGenerateChatSummaryAsync(ctx, logger, chat)
|
||||
|
||||
testutil.TryReceive(ctx, t, entered)
|
||||
|
||||
closed := make(chan struct{})
|
||||
go func() {
|
||||
defer close(closed)
|
||||
_ = server.Close()
|
||||
}()
|
||||
testutil.TryReceive(ctx, t, closed)
|
||||
}
|
||||
|
||||
func TestComputerUseProviderAndModelFromConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"charm.land/fantasy"
|
||||
"charm.land/fantasy/object"
|
||||
@@ -965,6 +966,211 @@ func generateManualTitle(
|
||||
return title, nil
|
||||
}
|
||||
|
||||
const chatSummaryGenerationPrompt = "You summarize an AI coding chat for a quick-reference popover. " +
|
||||
"Populate the summary field with 1 to 3 plain sentences describing what the conversation is about and what was accomplished or attempted. " +
|
||||
"Write about the conversation in the third person. " +
|
||||
"Preserve specific identifiers such as PR numbers, repo names, file paths, function names, and error messages. " +
|
||||
"Do not address the user, give instructions, or continue the task. " +
|
||||
"No markdown, lists, headings, code fences, or surrounding quotes."
|
||||
|
||||
const (
|
||||
// Bound the transcript so the summary call stays cheap and within context;
|
||||
// long chats keep head and tail turns (see renderChatSummaryTranscript).
|
||||
summaryTranscriptMaxRunes = 16000
|
||||
// Cap a single turn so one long message cannot dominate the budget.
|
||||
summaryTranscriptPerMessageMaxRunes = 4000
|
||||
summaryMaxOutputTokens = 512
|
||||
// Reject pathologically long or verbose summaries, with slack over the
|
||||
// 1-3 sentence target.
|
||||
summaryMaxRunes = 1000
|
||||
summaryMaxSentences = 6
|
||||
)
|
||||
|
||||
type generatedChatSummary struct {
|
||||
Summary string `json:"summary" description:"1-3 sentence summary of the whole chat"`
|
||||
}
|
||||
|
||||
// renderChatSummaryTranscript renders chat history as plain text for summary
|
||||
// generation. Plain text avoids provider tool-call pairing rules.
|
||||
func renderChatSummaryTranscript(messages []database.ChatMessage) string {
|
||||
lines := make([]string, 0, len(messages))
|
||||
for _, message := range messages {
|
||||
var role string
|
||||
switch message.Role {
|
||||
case database.ChatMessageRoleUser:
|
||||
role = "user"
|
||||
case database.ChatMessageRoleAssistant:
|
||||
role = "assistant"
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// Keep visible turns plus the compaction summary (model-only but
|
||||
// compressed); skip other model-only messages as noise.
|
||||
visible := message.Visibility == database.ChatMessageVisibilityBoth ||
|
||||
message.Visibility == database.ChatMessageVisibilityUser
|
||||
compactionSummary := message.Visibility == database.ChatMessageVisibilityModel &&
|
||||
message.Compressed
|
||||
if !visible && !compactionSummary {
|
||||
continue
|
||||
}
|
||||
|
||||
parts, err := chatprompt.ParseContent(message)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
text := strings.TrimSpace(contentBlocksToText(parts))
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
text = truncateRunes(text, summaryTranscriptPerMessageMaxRunes)
|
||||
lines = append(lines, fmt.Sprintf("[%s]: %s", role, text))
|
||||
}
|
||||
return boundTranscriptHeadTail(lines, summaryTranscriptMaxRunes)
|
||||
}
|
||||
|
||||
// boundTranscriptHeadTail joins lines; if over maxRunes it keeps a head and
|
||||
// tail slice with an elision marker between, preserving the chat's start and
|
||||
// most recent activity.
|
||||
func boundTranscriptHeadTail(lines []string, maxRunes int) string {
|
||||
if len(lines) == 0 {
|
||||
return ""
|
||||
}
|
||||
total := 0
|
||||
for _, line := range lines {
|
||||
total += len([]rune(line)) + 1
|
||||
}
|
||||
if total <= maxRunes {
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
half := maxRunes / 2
|
||||
headEnd := 0
|
||||
headRunes := 0
|
||||
for headEnd < len(lines) {
|
||||
n := len([]rune(lines[headEnd])) + 1
|
||||
if headEnd > 0 && headRunes+n > half {
|
||||
break
|
||||
}
|
||||
headRunes += n
|
||||
headEnd++
|
||||
}
|
||||
tailStart := len(lines)
|
||||
tailRunes := 0
|
||||
for tailStart > headEnd {
|
||||
n := len([]rune(lines[tailStart-1])) + 1
|
||||
if tailRunes+n > half {
|
||||
break
|
||||
}
|
||||
tailRunes += n
|
||||
tailStart--
|
||||
}
|
||||
|
||||
var out strings.Builder
|
||||
writeLine := func(line string) {
|
||||
if out.Len() > 0 {
|
||||
_ = out.WriteByte('\n')
|
||||
}
|
||||
_, _ = out.WriteString(line)
|
||||
}
|
||||
|
||||
for _, line := range lines[:headEnd] {
|
||||
writeLine(line)
|
||||
}
|
||||
if tailStart > headEnd {
|
||||
writeLine("[... earlier turns omitted ...]")
|
||||
}
|
||||
for _, line := range lines[tailStart:] {
|
||||
writeLine(line)
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// generateChatSummary generates a 1-3 sentence whole-chat summary from a
|
||||
// transcript. A blank or invalid result returns an error so callers preserve
|
||||
// any existing summary rather than clearing it.
|
||||
func generateChatSummary(
|
||||
ctx context.Context,
|
||||
model fantasy.LanguageModel,
|
||||
transcript string,
|
||||
) (string, fantasy.Usage, error) {
|
||||
transcript = strings.TrimSpace(transcript)
|
||||
if transcript == "" {
|
||||
return "", fantasy.Usage{}, xerrors.New("chat summary transcript was empty")
|
||||
}
|
||||
|
||||
prompt := fantasy.Prompt{
|
||||
{
|
||||
Role: fantasy.MessageRoleSystem,
|
||||
Content: []fantasy.MessagePart{
|
||||
fantasy.TextPart{Text: chatSummaryGenerationPrompt},
|
||||
},
|
||||
},
|
||||
{
|
||||
Role: fantasy.MessageRoleUser,
|
||||
Content: []fantasy.MessagePart{
|
||||
fantasy.TextPart{Text: transcript},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
maxOutputTokens := int64(summaryMaxOutputTokens)
|
||||
var result *fantasy.ObjectResult[generatedChatSummary]
|
||||
err := chatretry.Retry(ctx, func(retryCtx context.Context) error {
|
||||
var genErr error
|
||||
result, genErr = object.Generate[generatedChatSummary](retryCtx, model, fantasy.ObjectCall{
|
||||
Prompt: prompt,
|
||||
SchemaName: "chat_summary",
|
||||
SchemaDescription: "Summarize the whole chat in 1-3 sentences.",
|
||||
MaxOutputTokens: &maxOutputTokens,
|
||||
})
|
||||
return genErr
|
||||
}, nil)
|
||||
if err != nil {
|
||||
var usage fantasy.Usage
|
||||
if noObjErr, ok := errors.AsType[*fantasy.NoObjectGeneratedError](err); ok {
|
||||
usage = noObjErr.Usage
|
||||
}
|
||||
return "", usage, xerrors.Errorf("generate chat summary: %w", err)
|
||||
}
|
||||
|
||||
summary := normalizeShortTextOutput(result.Object.Summary)
|
||||
if err := validateGeneratedChatSummary(summary); err != nil {
|
||||
return "", result.Usage, err
|
||||
}
|
||||
return summary, result.Usage, nil
|
||||
}
|
||||
|
||||
func validateGeneratedChatSummary(summary string) error {
|
||||
if summary == "" {
|
||||
return xerrors.New("generated chat summary was empty")
|
||||
}
|
||||
if len([]rune(summary)) > summaryMaxRunes {
|
||||
return xerrors.Errorf("generated chat summary exceeded %d runes", summaryMaxRunes)
|
||||
}
|
||||
if countSentenceTerminators(summary) > summaryMaxSentences {
|
||||
return xerrors.Errorf("generated chat summary exceeded %d sentences", summaryMaxSentences)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// countSentenceTerminators counts sentence-ending punctuation, but only when
|
||||
// followed by whitespace or end-of-text, so periods inside dotted identifiers
|
||||
// (pkg.cmd.server, file paths) do not inflate the count.
|
||||
func countSentenceTerminators(text string) int {
|
||||
runes := []rune(text)
|
||||
count := 0
|
||||
for i, r := range runes {
|
||||
if r != '.' && r != '!' && r != '?' {
|
||||
continue
|
||||
}
|
||||
if i == len(runes)-1 || unicode.IsSpace(runes[i+1]) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
const turnStatusLabelPrompt = "You write compact chat status labels for a sidebar or push notification. " +
|
||||
"Given a chat title, current chat state, and the agent's latest message, populate the label field with a 2-5 word status label. " +
|
||||
"Describe the chat's current state, not the agent. " +
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
package chatd
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/x/chatd/chatprompt"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
func summaryTestMessage(
|
||||
t *testing.T,
|
||||
id int64,
|
||||
role database.ChatMessageRole,
|
||||
visibility database.ChatMessageVisibility,
|
||||
parts []codersdk.ChatMessagePart,
|
||||
compressed bool,
|
||||
createdAt time.Time,
|
||||
) database.ChatMessage {
|
||||
t.Helper()
|
||||
content, err := chatprompt.MarshalParts(parts)
|
||||
require.NoError(t, err)
|
||||
return database.ChatMessage{
|
||||
ID: id,
|
||||
Role: role,
|
||||
Visibility: visibility,
|
||||
Content: content,
|
||||
ContentVersion: chatprompt.CurrentContentVersion,
|
||||
Compressed: compressed,
|
||||
CreatedAt: createdAt,
|
||||
}
|
||||
}
|
||||
|
||||
func summaryTextMessage(
|
||||
t *testing.T,
|
||||
id int64,
|
||||
role database.ChatMessageRole,
|
||||
visibility database.ChatMessageVisibility,
|
||||
text string,
|
||||
compressed bool,
|
||||
createdAt time.Time,
|
||||
) database.ChatMessage {
|
||||
t.Helper()
|
||||
return summaryTestMessage(t, id, role, visibility,
|
||||
[]codersdk.ChatMessagePart{codersdk.ChatMessageText(text)},
|
||||
compressed, createdAt)
|
||||
}
|
||||
|
||||
func TestRenderChatSummaryTranscript(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
base := time.Date(2026, 6, 24, 0, 0, 0, 0, time.UTC)
|
||||
messages := []database.ChatMessage{
|
||||
summaryTextMessage(t, 1, database.ChatMessageRoleUser, database.ChatMessageVisibilityModel, "you are a helpful agent", false, base),
|
||||
// Compaction summary (model-only but compressed) is kept.
|
||||
summaryTextMessage(t, 2, database.ChatMessageRoleUser, database.ChatMessageVisibilityModel, "earlier work compaction summary", true, base.Add(time.Minute)),
|
||||
// Injected context (model-only, not compressed) is skipped as noise.
|
||||
summaryTextMessage(t, 3, database.ChatMessageRoleUser, database.ChatMessageVisibilityModel, "AGENTS.md injected context", false, base.Add(2*time.Minute)),
|
||||
summaryTextMessage(t, 4, database.ChatMessageRoleUser, database.ChatMessageVisibilityBoth, "fix the bug in foo.go", false, base.Add(3*time.Minute)),
|
||||
summaryTextMessage(t, 8, database.ChatMessageRoleUser, database.ChatMessageVisibilityUser, "and please keep it simple", false, base.Add(3*time.Minute+30*time.Second)),
|
||||
summaryTestMessage(t, 5, database.ChatMessageRoleAssistant, database.ChatMessageVisibilityBoth,
|
||||
[]codersdk.ChatMessagePart{codersdk.ChatMessageToolCall("call-1", "bash", []byte(`{"cmd":"go test"}`))},
|
||||
false, base.Add(4*time.Minute)),
|
||||
summaryTextMessage(t, 6, database.ChatMessageRoleTool, database.ChatMessageVisibilityBoth, "tests passed", false, base.Add(5*time.Minute)),
|
||||
summaryTextMessage(t, 7, database.ChatMessageRoleAssistant, database.ChatMessageVisibilityBoth, "fixed the bug and added a test", false, base.Add(6*time.Minute)),
|
||||
}
|
||||
|
||||
transcript := renderChatSummaryTranscript(messages)
|
||||
|
||||
require.Contains(t, transcript, "earlier work compaction summary")
|
||||
require.Contains(t, transcript, "[user]: fix the bug in foo.go")
|
||||
require.Contains(t, transcript, "[user]: and please keep it simple")
|
||||
require.Contains(t, transcript, "[assistant]: fixed the bug and added a test")
|
||||
// System prompt, injected context, tool-call, and tool result are excluded.
|
||||
require.NotContains(t, transcript, "you are a helpful agent")
|
||||
require.NotContains(t, transcript, "AGENTS.md injected context")
|
||||
require.NotContains(t, transcript, "tests passed")
|
||||
require.NotContains(t, transcript, "go test")
|
||||
}
|
||||
|
||||
func TestBoundTranscriptHeadTail(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("UnderBudgetReturnsAll", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
lines := []string{"a", "b", "c"}
|
||||
require.Equal(t, "a\nb\nc", boundTranscriptHeadTail(lines, 1000))
|
||||
})
|
||||
|
||||
t.Run("OverBudgetKeepsHeadAndTail", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
lines := []string{
|
||||
"HEAD-FIRST " + strings.Repeat("x", 40),
|
||||
strings.Repeat("m", 200),
|
||||
strings.Repeat("n", 200),
|
||||
strings.Repeat("o", 200),
|
||||
"TAIL-LAST " + strings.Repeat("y", 40),
|
||||
}
|
||||
out := boundTranscriptHeadTail(lines, 160)
|
||||
require.Contains(t, out, "HEAD-FIRST")
|
||||
require.Contains(t, out, "TAIL-LAST")
|
||||
require.Contains(t, out, "[... earlier turns omitted ...]")
|
||||
})
|
||||
}
|
||||
|
||||
func TestShouldGenerateChatSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
base := time.Date(2026, 6, 24, 0, 0, 0, 0, time.UTC)
|
||||
userMsg := func(id int64, at time.Time) database.ChatMessage {
|
||||
return database.ChatMessage{
|
||||
ID: id,
|
||||
Role: database.ChatMessageRoleUser,
|
||||
Visibility: database.ChatMessageVisibilityBoth,
|
||||
CreatedAt: at,
|
||||
}
|
||||
}
|
||||
assistantMsg := func(id int64, at time.Time) database.ChatMessage {
|
||||
return database.ChatMessage{
|
||||
ID: id,
|
||||
Role: database.ChatMessageRoleAssistant,
|
||||
Visibility: database.ChatMessageVisibilityBoth,
|
||||
CreatedAt: at,
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("FirstSummaryAtFirstTurn", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
chat := database.Chat{}
|
||||
msgs := []database.ChatMessage{
|
||||
userMsg(1, base),
|
||||
assistantMsg(2, base.Add(time.Minute)),
|
||||
}
|
||||
require.True(t, shouldGenerateChatSummary(chat, msgs))
|
||||
})
|
||||
|
||||
t.Run("FirstSummarySkippedWithNoTurns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
chat := database.Chat{}
|
||||
require.False(t, shouldGenerateChatSummary(chat, nil))
|
||||
})
|
||||
|
||||
t.Run("MultiStepTurnDoesNotInflateCount", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
marker := base
|
||||
chat := database.Chat{
|
||||
Summary: sql.NullString{String: "existing", Valid: true},
|
||||
SummaryGeneratedAt: sql.NullTime{Time: marker, Valid: true},
|
||||
}
|
||||
// One user turn plus many assistant steps stays below the threshold.
|
||||
msgs := []database.ChatMessage{
|
||||
userMsg(1, marker.Add(time.Minute)),
|
||||
assistantMsg(2, marker.Add(2*time.Minute)),
|
||||
assistantMsg(3, marker.Add(3*time.Minute)),
|
||||
assistantMsg(4, marker.Add(4*time.Minute)),
|
||||
}
|
||||
require.False(t, shouldGenerateChatSummary(chat, msgs))
|
||||
})
|
||||
|
||||
t.Run("ModelOnlyUserMessagesAreNotTurns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
marker := base
|
||||
chat := database.Chat{
|
||||
Summary: sql.NullString{String: "existing", Valid: true},
|
||||
SummaryGeneratedAt: sql.NullTime{Time: marker, Valid: true},
|
||||
}
|
||||
modelOnlyUserMsg := func(id int64, at time.Time) database.ChatMessage {
|
||||
return database.ChatMessage{
|
||||
ID: id,
|
||||
Role: database.ChatMessageRoleUser,
|
||||
Visibility: database.ChatMessageVisibilityModel,
|
||||
CreatedAt: at,
|
||||
}
|
||||
}
|
||||
// The model-only user message must not count as a turn, else these
|
||||
// three messages would trip the threshold of 3.
|
||||
msgs := []database.ChatMessage{
|
||||
userMsg(1, marker.Add(time.Minute)),
|
||||
modelOnlyUserMsg(2, marker.Add(2*time.Minute)),
|
||||
userMsg(3, marker.Add(3*time.Minute)),
|
||||
}
|
||||
require.False(t, shouldGenerateChatSummary(chat, msgs))
|
||||
})
|
||||
|
||||
t.Run("RefreshAfterThresholdTurns", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
marker := base
|
||||
chat := database.Chat{
|
||||
Summary: sql.NullString{String: "existing", Valid: true},
|
||||
SummaryGeneratedAt: sql.NullTime{Time: marker, Valid: true},
|
||||
}
|
||||
msgs := []database.ChatMessage{
|
||||
// Pre-marker turn is not counted.
|
||||
userMsg(1, marker.Add(-time.Minute)),
|
||||
userMsg(2, marker.Add(time.Minute)),
|
||||
userMsg(3, marker.Add(2*time.Minute)),
|
||||
userMsg(4, marker.Add(3*time.Minute)),
|
||||
}
|
||||
require.True(t, shouldGenerateChatSummary(chat, msgs))
|
||||
})
|
||||
|
||||
t.Run("PreMarkerTurnsAreNotCounted", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
marker := base
|
||||
chat := database.Chat{
|
||||
Summary: sql.NullString{String: "existing", Valid: true},
|
||||
SummaryGeneratedAt: sql.NullTime{Time: marker, Valid: true},
|
||||
}
|
||||
// The pre-marker turn would tip the total to the threshold; this stays
|
||||
// false only because countCompletedTurnsSince excludes pre-marker turns.
|
||||
msgs := []database.ChatMessage{
|
||||
userMsg(1, marker.Add(-time.Minute)),
|
||||
userMsg(2, marker.Add(time.Minute)),
|
||||
userMsg(3, marker.Add(2*time.Minute)),
|
||||
}
|
||||
require.False(t, shouldGenerateChatSummary(chat, msgs))
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidateGeneratedChatSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require.Error(t, validateGeneratedChatSummary(""))
|
||||
require.Error(t, validateGeneratedChatSummary(strings.Repeat("a", summaryMaxRunes+1)))
|
||||
require.Error(t, validateGeneratedChatSummary("One. Two. Three. Four. Five. Six. Seven."))
|
||||
require.NoError(t, validateGeneratedChatSummary("Implemented the summary feature. Added tests."))
|
||||
}
|
||||
|
||||
func TestCountSentenceTerminators(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Periods inside dotted identifiers (pkg.cmd.server) are not boundaries.
|
||||
require.Equal(t, 2, countSentenceTerminators("Fixed pkg.cmd.server in file.go. Added a test."))
|
||||
require.Equal(t, 3, countSentenceTerminators("One. Two! Three?"))
|
||||
require.Equal(t, 0, countSentenceTerminators("auth.rbac.Policy"))
|
||||
|
||||
// Dotted identifiers must not push a valid summary over the sentence cap.
|
||||
require.NoError(t, validateGeneratedChatSummary(
|
||||
"Refactored pkg.cmd.server and auth.rbac.Policy in main.go and util.go. Added coverage in foo_test.go.",
|
||||
))
|
||||
}
|
||||
+35
-28
@@ -105,27 +105,30 @@ const (
|
||||
|
||||
// Chat represents a chat session with an AI agent.
|
||||
type Chat struct {
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
|
||||
OwnerID uuid.UUID `json:"owner_id" format:"uuid"`
|
||||
OwnerUsername string `json:"owner_username,omitempty"`
|
||||
OwnerName string `json:"owner_name,omitempty"`
|
||||
WorkspaceID *uuid.UUID `json:"workspace_id,omitempty" format:"uuid"`
|
||||
BuildID *uuid.UUID `json:"build_id,omitempty" format:"uuid"`
|
||||
AgentID *uuid.UUID `json:"agent_id,omitempty" format:"uuid"`
|
||||
ParentChatID *uuid.UUID `json:"parent_chat_id,omitempty" format:"uuid"`
|
||||
RootChatID *uuid.UUID `json:"root_chat_id,omitempty" format:"uuid"`
|
||||
LastModelConfigID uuid.UUID `json:"last_model_config_id" format:"uuid"`
|
||||
LastReasoningEffort *string `json:"last_reasoning_effort,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Status ChatStatus `json:"status"`
|
||||
PlanMode ChatPlanMode `json:"plan_mode,omitempty"`
|
||||
LastError *ChatError `json:"last_error,omitempty"`
|
||||
LastTurnSummary *string `json:"last_turn_summary"`
|
||||
DiffStatus *ChatDiffStatus `json:"diff_status,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
Archived bool `json:"archived"`
|
||||
ID uuid.UUID `json:"id" format:"uuid"`
|
||||
OrganizationID uuid.UUID `json:"organization_id" format:"uuid"`
|
||||
OwnerID uuid.UUID `json:"owner_id" format:"uuid"`
|
||||
OwnerUsername string `json:"owner_username,omitempty"`
|
||||
OwnerName string `json:"owner_name,omitempty"`
|
||||
WorkspaceID *uuid.UUID `json:"workspace_id,omitempty" format:"uuid"`
|
||||
BuildID *uuid.UUID `json:"build_id,omitempty" format:"uuid"`
|
||||
AgentID *uuid.UUID `json:"agent_id,omitempty" format:"uuid"`
|
||||
ParentChatID *uuid.UUID `json:"parent_chat_id,omitempty" format:"uuid"`
|
||||
RootChatID *uuid.UUID `json:"root_chat_id,omitempty" format:"uuid"`
|
||||
LastModelConfigID uuid.UUID `json:"last_model_config_id" format:"uuid"`
|
||||
LastReasoningEffort *string `json:"last_reasoning_effort,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Status ChatStatus `json:"status"`
|
||||
PlanMode ChatPlanMode `json:"plan_mode,omitempty"`
|
||||
LastError *ChatError `json:"last_error,omitempty"`
|
||||
LastTurnSummary *string `json:"last_turn_summary"`
|
||||
// Summary is the persisted whole-chat summary, generated in the background.
|
||||
// It is nil until the first summary has been produced.
|
||||
Summary *string `json:"summary"`
|
||||
DiffStatus *ChatDiffStatus `json:"diff_status,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at" format:"date-time"`
|
||||
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
|
||||
Archived bool `json:"archived"`
|
||||
// Shared is true when this chat's root chat has explicit user or group ACL entries.
|
||||
Shared bool `json:"shared"`
|
||||
PinOrder int32 `json:"pin_order"`
|
||||
@@ -1860,13 +1863,17 @@ func NewDynamicTool[T any](
|
||||
type ChatWatchEventKind string
|
||||
|
||||
const (
|
||||
ChatWatchEventKindStatusChange ChatWatchEventKind = "status_change"
|
||||
ChatWatchEventKindSummaryChange ChatWatchEventKind = "summary_change"
|
||||
ChatWatchEventKindTitleChange ChatWatchEventKind = "title_change"
|
||||
ChatWatchEventKindCreated ChatWatchEventKind = "created"
|
||||
ChatWatchEventKindDeleted ChatWatchEventKind = "deleted"
|
||||
ChatWatchEventKindDiffStatusChange ChatWatchEventKind = "diff_status_change"
|
||||
ChatWatchEventKindActionRequired ChatWatchEventKind = "action_required"
|
||||
ChatWatchEventKindStatusChange ChatWatchEventKind = "status_change"
|
||||
ChatWatchEventKindSummaryChange ChatWatchEventKind = "summary_change"
|
||||
// ChatWatchEventKindChatSummaryChange carries the persisted whole-chat
|
||||
// summary. It is distinct from SummaryChange (bound to last_turn_summary) so
|
||||
// the frontend updates one field without disturbing the other.
|
||||
ChatWatchEventKindChatSummaryChange ChatWatchEventKind = "chat_summary_change"
|
||||
ChatWatchEventKindTitleChange ChatWatchEventKind = "title_change"
|
||||
ChatWatchEventKindCreated ChatWatchEventKind = "created"
|
||||
ChatWatchEventKindDeleted ChatWatchEventKind = "deleted"
|
||||
ChatWatchEventKindDiffStatusChange ChatWatchEventKind = "diff_status_change"
|
||||
ChatWatchEventKindActionRequired ChatWatchEventKind = "action_required"
|
||||
// ChatWatchEventKindContextDirty signals that the chat's pinned
|
||||
// workspace context changed: it drifted from the agent's latest
|
||||
// pushed snapshot, or hydration first populated it (a first-turn
|
||||
|
||||
@@ -13,41 +13,41 @@ We track the following resources:
|
||||
|
||||
<!-- Code generated by 'make docs/admin/security/audit-logs.md'. DO NOT EDIT -->
|
||||
|
||||
| <b>Resource</b> | | |
|
||||
|-----------------------------------------------------------------|----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| AIGatewayKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>hashed_secret</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_heartbeat_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>secret_prefix</td><td>true</td></tr></tbody></table> |
|
||||
| AIProvider<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>base_url</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>enabled</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>settings</td><td>true</td></tr><tr><td>settings_key_id</td><td>false</td></tr><tr><td>type</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AIProviderKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>api_key</td><td>true</td></tr><tr><td>api_key_key_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>provider_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AISeatState<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>first_used_at</td><td>true</td></tr><tr><td>last_event_description</td><td>true</td></tr><tr><td>last_event_type</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| APIKey<br><i>login, logout, register, create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>allow_list</td><td>false</td></tr><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>ip_address</td><td>false</td></tr><tr><td>last_used</td><td>true</td></tr><tr><td>lifetime_seconds</td><td>false</td></tr><tr><td>login_type</td><td>false</td></tr><tr><td>scopes</td><td>false</td></tr><tr><td>token_name</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>true</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableGroupAIBudget<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>group_id</td><td>false</td></tr><tr><td>group_name</td><td>false</td></tr><tr><td>spend_limit</td><td>true</td></tr><tr><td>spend_limit_micros</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableOrganizationMember<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>roles</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| AuditableUserAIBudgetOverride<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>group_id</td><td>true</td></tr><tr><td>group_name</td><td>true</td></tr><tr><td>spend_limit</td><td>true</td></tr><tr><td>spend_limit_micros</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>false</td></tr><tr><td>username</td><td>false</td></tr></tbody></table> |
|
||||
| Chat<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>agent_id</td><td>false</td></tr><tr><td>archived</td><td>true</td></tr><tr><td>build_id</td><td>false</td></tr><tr><td>client_type</td><td>false</td></tr><tr><td>compaction_requested_at</td><td>false</td></tr><tr><td>context_aggregate_hash</td><td>false</td></tr><tr><td>context_dirty_resources</td><td>false</td></tr><tr><td>context_dirty_since</td><td>false</td></tr><tr><td>context_error</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamic_tools</td><td>false</td></tr><tr><td>generation_attempt</td><td>false</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>heartbeat_at</td><td>false</td></tr><tr><td>history_version</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>labels</td><td>true</td></tr><tr><td>last_error</td><td>false</td></tr><tr><td>last_model_config_id</td><td>false</td></tr><tr><td>last_read_message_id</td><td>false</td></tr><tr><td>last_reasoning_effort</td><td>false</td></tr><tr><td>last_turn_summary</td><td>false</td></tr><tr><td>mcp_server_ids</td><td>true</td></tr><tr><td>mode</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>owner_name</td><td>false</td></tr><tr><td>owner_username</td><td>false</td></tr><tr><td>parent_chat_id</td><td>false</td></tr><tr><td>pin_order</td><td>true</td></tr><tr><td>plan_mode</td><td>false</td></tr><tr><td>queue_version</td><td>false</td></tr><tr><td>requires_action_deadline_at</td><td>false</td></tr><tr><td>retry_state</td><td>false</td></tr><tr><td>retry_state_version</td><td>false</td></tr><tr><td>root_chat_id</td><td>false</td></tr><tr><td>runner_id</td><td>false</td></tr><tr><td>snapshot_version</td><td>false</td></tr><tr><td>started_at</td><td>false</td></tr><tr><td>status</td><td>false</td></tr><tr><td>title</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr><tr><td>worker_id</td><td>false</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| CustomRole<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_system</td><td>false</td></tr><tr><td>member_permissions</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>org_permissions</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>site_permissions</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_permissions</td><td>true</td></tr></tbody></table> |
|
||||
| GitSSHKey<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>private_key</td><td>true</td></tr><tr><td>private_key_key_id</td><td>false</td></tr><tr><td>public_key</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| GroupSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>auto_create_missing_groups</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>legacy_group_name_mapping</td><td>false</td></tr><tr><td>mapping</td><td>true</td></tr><tr><td>regex_filter</td><td>true</td></tr></tbody></table> |
|
||||
| HealthSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>dismissed_healthchecks</td><td>true</td></tr><tr><td>id</td><td>false</td></tr></tbody></table> |
|
||||
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationTemplate<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>actions</td><td>true</td></tr><tr><td>body_template</td><td>true</td></tr><tr><td>enabled_by_default</td><td>true</td></tr><tr><td>group</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>kind</td><td>true</td></tr><tr><td>method</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>title_template</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>notifier_paused</td><td>true</td></tr></tbody></table> |
|
||||
| OAuth2ProviderApp<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>callback_url</td><td>true</td></tr><tr><td>client_id_issued_at</td><td>false</td></tr><tr><td>client_secret_expires_at</td><td>true</td></tr><tr><td>client_type</td><td>true</td></tr><tr><td>client_uri</td><td>true</td></tr><tr><td>contacts</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamically_registered</td><td>true</td></tr><tr><td>grant_types</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwks</td><td>true</td></tr><tr><td>jwks_uri</td><td>true</td></tr><tr><td>logo_uri</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>policy_uri</td><td>true</td></tr><tr><td>redirect_uris</td><td>true</td></tr><tr><td>registration_access_token</td><td>true</td></tr><tr><td>registration_client_uri</td><td>true</td></tr><tr><td>response_types</td><td>true</td></tr><tr><td>scope</td><td>true</td></tr><tr><td>software_id</td><td>true</td></tr><tr><td>software_version</td><td>true</td></tr><tr><td>token_endpoint_auth_method</td><td>true</td></tr><tr><td>tos_uri</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| OAuth2ProviderAppSecret<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>app_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>display_secret</td><td>false</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>secret_prefix</td><td>false</td></tr></tbody></table> |
|
||||
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>default_org_member_roles</td><td>true</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>shareable_workspace_owners</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
||||
| OrganizationSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>assign_default</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| PrebuildsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>reconciliation_paused</td><td>true</td></tr></tbody></table> |
|
||||
| RoleSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| TaskTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>prompt</td><td>true</td></tr><tr><td>template_parameters</td><td>true</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>cors_behavior</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>disable_module_cache</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_autostop_notify</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_classic_parameter_flow</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>false</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>is_service_account</td><td>true</td></tr><tr><td>is_system</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| UserSecret<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>env_name</td><td>true</td></tr><tr><td>file_path</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>value</td><td>true</td></tr><tr><td>value_key_id</td><td>false</td></tr></tbody></table> |
|
||||
| UserSkill<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>content</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_name</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>notified_autostop_deadline</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>template_version_preset_id</td><td>false</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
||||
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>next_start_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| <b>Resource</b> | | |
|
||||
|-----------------------------------------------------------------|----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| AIGatewayKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>hashed_secret</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_heartbeat_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>secret_prefix</td><td>true</td></tr></tbody></table> |
|
||||
| AIProvider<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>base_url</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>enabled</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>settings</td><td>true</td></tr><tr><td>settings_key_id</td><td>false</td></tr><tr><td>type</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AIProviderKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>api_key</td><td>true</td></tr><tr><td>api_key_key_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>provider_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AISeatState<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>first_used_at</td><td>true</td></tr><tr><td>last_event_description</td><td>true</td></tr><tr><td>last_event_type</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| APIKey<br><i>login, logout, register, create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>allow_list</td><td>false</td></tr><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>ip_address</td><td>false</td></tr><tr><td>last_used</td><td>true</td></tr><tr><td>lifetime_seconds</td><td>false</td></tr><tr><td>login_type</td><td>false</td></tr><tr><td>scopes</td><td>false</td></tr><tr><td>token_name</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>true</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableGroupAIBudget<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>group_id</td><td>false</td></tr><tr><td>group_name</td><td>false</td></tr><tr><td>spend_limit</td><td>true</td></tr><tr><td>spend_limit_micros</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableOrganizationMember<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>roles</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| AuditableUserAIBudgetOverride<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>group_id</td><td>true</td></tr><tr><td>group_name</td><td>true</td></tr><tr><td>spend_limit</td><td>true</td></tr><tr><td>spend_limit_micros</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>false</td></tr><tr><td>username</td><td>false</td></tr></tbody></table> |
|
||||
| Chat<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>agent_id</td><td>false</td></tr><tr><td>archived</td><td>true</td></tr><tr><td>build_id</td><td>false</td></tr><tr><td>client_type</td><td>false</td></tr><tr><td>compaction_requested_at</td><td>false</td></tr><tr><td>context_aggregate_hash</td><td>false</td></tr><tr><td>context_dirty_resources</td><td>false</td></tr><tr><td>context_dirty_since</td><td>false</td></tr><tr><td>context_error</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamic_tools</td><td>false</td></tr><tr><td>generation_attempt</td><td>false</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>heartbeat_at</td><td>false</td></tr><tr><td>history_version</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>labels</td><td>true</td></tr><tr><td>last_error</td><td>false</td></tr><tr><td>last_model_config_id</td><td>false</td></tr><tr><td>last_read_message_id</td><td>false</td></tr><tr><td>last_reasoning_effort</td><td>false</td></tr><tr><td>last_turn_summary</td><td>false</td></tr><tr><td>mcp_server_ids</td><td>true</td></tr><tr><td>mode</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>owner_name</td><td>false</td></tr><tr><td>owner_username</td><td>false</td></tr><tr><td>parent_chat_id</td><td>false</td></tr><tr><td>pin_order</td><td>true</td></tr><tr><td>plan_mode</td><td>false</td></tr><tr><td>queue_version</td><td>false</td></tr><tr><td>requires_action_deadline_at</td><td>false</td></tr><tr><td>retry_state</td><td>false</td></tr><tr><td>retry_state_version</td><td>false</td></tr><tr><td>root_chat_id</td><td>false</td></tr><tr><td>runner_id</td><td>false</td></tr><tr><td>snapshot_version</td><td>false</td></tr><tr><td>started_at</td><td>false</td></tr><tr><td>status</td><td>false</td></tr><tr><td>summary</td><td>false</td></tr><tr><td>summary_generated_at</td><td>false</td></tr><tr><td>title</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr><tr><td>worker_id</td><td>false</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| CustomRole<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_system</td><td>false</td></tr><tr><td>member_permissions</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>org_permissions</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>site_permissions</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_permissions</td><td>true</td></tr></tbody></table> |
|
||||
| GitSSHKey<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>private_key</td><td>true</td></tr><tr><td>private_key_key_id</td><td>false</td></tr><tr><td>public_key</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| GroupSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>auto_create_missing_groups</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>legacy_group_name_mapping</td><td>false</td></tr><tr><td>mapping</td><td>true</td></tr><tr><td>regex_filter</td><td>true</td></tr></tbody></table> |
|
||||
| HealthSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>dismissed_healthchecks</td><td>true</td></tr><tr><td>id</td><td>false</td></tr></tbody></table> |
|
||||
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationTemplate<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>actions</td><td>true</td></tr><tr><td>body_template</td><td>true</td></tr><tr><td>enabled_by_default</td><td>true</td></tr><tr><td>group</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>kind</td><td>true</td></tr><tr><td>method</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>title_template</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>notifier_paused</td><td>true</td></tr></tbody></table> |
|
||||
| OAuth2ProviderApp<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>callback_url</td><td>true</td></tr><tr><td>client_id_issued_at</td><td>false</td></tr><tr><td>client_secret_expires_at</td><td>true</td></tr><tr><td>client_type</td><td>true</td></tr><tr><td>client_uri</td><td>true</td></tr><tr><td>contacts</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamically_registered</td><td>true</td></tr><tr><td>grant_types</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwks</td><td>true</td></tr><tr><td>jwks_uri</td><td>true</td></tr><tr><td>logo_uri</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>policy_uri</td><td>true</td></tr><tr><td>redirect_uris</td><td>true</td></tr><tr><td>registration_access_token</td><td>true</td></tr><tr><td>registration_client_uri</td><td>true</td></tr><tr><td>response_types</td><td>true</td></tr><tr><td>scope</td><td>true</td></tr><tr><td>software_id</td><td>true</td></tr><tr><td>software_version</td><td>true</td></tr><tr><td>token_endpoint_auth_method</td><td>true</td></tr><tr><td>tos_uri</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| OAuth2ProviderAppSecret<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>app_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>display_secret</td><td>false</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>secret_prefix</td><td>false</td></tr></tbody></table> |
|
||||
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>default_org_member_roles</td><td>true</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>shareable_workspace_owners</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
||||
| OrganizationSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>assign_default</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| PrebuildsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>reconciliation_paused</td><td>true</td></tr></tbody></table> |
|
||||
| RoleSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| TaskTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>prompt</td><td>true</td></tr><tr><td>template_parameters</td><td>true</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>cors_behavior</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>disable_module_cache</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_autostop_notify</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_classic_parameter_flow</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>false</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>is_service_account</td><td>true</td></tr><tr><td>is_system</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| UserSecret<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>env_name</td><td>true</td></tr><tr><td>file_path</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>value</td><td>true</td></tr><tr><td>value_key_id</td><td>false</td></tr></tbody></table> |
|
||||
| UserSkill<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>content</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_name</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>notified_autostop_deadline</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>template_version_preset_id</td><td>false</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
||||
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>next_start_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
|
||||
<!-- End generated by 'make docs/admin/security/audit-logs.md'. -->
|
||||
|
||||
|
||||
Generated
+15
@@ -122,6 +122,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -218,6 +219,7 @@ Status Code **200**
|
||||
| `» root_chat_id` | string(uuid) | false | | |
|
||||
| `» shared` | boolean | false | | Shared is true when this chat's root chat has explicit user or group ACL entries. |
|
||||
| `» status` | [codersdk.ChatStatus](schemas.md#codersdkchatstatus) | false | | |
|
||||
| `» summary` | string | false | | Summary is the persisted whole-chat summary, generated in the background. It is nil until the first summary has been produced. |
|
||||
| `» title` | string | false | | |
|
||||
| `» updated_at` | string(date-time) | false | | |
|
||||
| `» warnings` | array | false | | |
|
||||
@@ -397,6 +399,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -490,6 +493,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -740,6 +744,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -887,6 +892,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -980,6 +986,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -1164,6 +1171,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -1257,6 +1265,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -1439,6 +1448,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -1532,6 +1542,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -2283,6 +2294,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -2376,6 +2388,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -2883,6 +2896,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -2976,6 +2990,7 @@ Experimental: this endpoint is subject to change.
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
|
||||
Generated
+7
-3
@@ -2164,6 +2164,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -2257,6 +2258,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -2298,6 +2300,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
| `root_chat_id` | string | false | | |
|
||||
| `shared` | boolean | false | | Shared is true when this chat's root chat has explicit user or group ACL entries. |
|
||||
| `status` | [codersdk.ChatStatus](#codersdkchatstatus) | false | | |
|
||||
| `summary` | string | false | | Summary is the persisted whole-chat summary, generated in the background. It is nil until the first summary has been produced. |
|
||||
| `title` | string | false | | |
|
||||
| `updated_at` | string | false | | |
|
||||
| `warnings` | array of string | false | | |
|
||||
@@ -4042,6 +4045,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
"root_chat_id": "2898031c-fdce-4e3e-8c53-4481dd42fcd7",
|
||||
"shared": true,
|
||||
"status": "waiting",
|
||||
"summary": "string",
|
||||
"title": "string",
|
||||
"updated_at": "2019-08-24T14:15:22Z",
|
||||
"warnings": [
|
||||
@@ -4078,9 +4082,9 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Value(s) |
|
||||
|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `action_required`, `context_dirty`, `created`, `deleted`, `diff_status_change`, `status_change`, `summary_change`, `title_change` |
|
||||
| Value(s) |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `action_required`, `chat_summary_change`, `context_dirty`, `created`, `deleted`, `diff_status_change`, `status_change`, `summary_change`, `title_change` |
|
||||
|
||||
## codersdk.ClusterConfig
|
||||
|
||||
|
||||
@@ -461,6 +461,8 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||
"archived": ActionTrack,
|
||||
"last_error": ActionIgnore, // Internal.
|
||||
"last_turn_summary": ActionIgnore, // Internal cached display text.
|
||||
"summary": ActionIgnore, // Internal cached display text, generated asynchronously.
|
||||
"summary_generated_at": ActionIgnore, // Internal freshness marker for the cached summary.
|
||||
"mode": ActionTrack,
|
||||
"mcp_server_ids": ActionTrack,
|
||||
"labels": ActionTrack,
|
||||
|
||||
@@ -125,6 +125,7 @@ const makeChat = (
|
||||
has_unread: false,
|
||||
client_type: "ui",
|
||||
last_turn_summary: null,
|
||||
summary: null,
|
||||
children: [],
|
||||
...overrides,
|
||||
});
|
||||
@@ -2294,6 +2295,71 @@ describe("mergeWatchedChatSummary", () => {
|
||||
).toBe("Fixed the issue");
|
||||
});
|
||||
|
||||
it("applies chat_summary_change even when event updated_at is older", () => {
|
||||
const cachedChat = makeChat("chat-1", {
|
||||
summary: null,
|
||||
last_turn_summary: "Latest turn",
|
||||
updated_at: "2025-01-01T00:05:00.000Z",
|
||||
});
|
||||
const watchedChat = makeChat("chat-1", {
|
||||
summary: "Implemented the whole-chat summary feature.",
|
||||
// chat_summary_change preserves updated_at, so the event carries an
|
||||
// equal-or-older timestamp than the cached chat.
|
||||
last_turn_summary: "Stale turn",
|
||||
updated_at: "2025-01-01T00:00:00.000Z",
|
||||
});
|
||||
|
||||
const merged = mergeWatchedChatSummary(cachedChat, watchedChat, {
|
||||
eventKind: "chat_summary_change",
|
||||
});
|
||||
expect(merged.summary).toBe("Implemented the whole-chat summary feature.");
|
||||
// A chat_summary_change event must not clobber last_turn_summary with the
|
||||
// event's stale snapshot.
|
||||
expect(merged.last_turn_summary).toBe("Latest turn");
|
||||
});
|
||||
|
||||
it("does not clobber the whole-chat summary on a summary_change with equal updated_at", () => {
|
||||
const cachedChat = makeChat("chat-1", {
|
||||
summary: "Whole-chat summary.",
|
||||
last_turn_summary: "Old turn",
|
||||
updated_at: "2025-01-01T00:00:00.000Z",
|
||||
});
|
||||
// Neither summary write bumps chats.updated_at, so both events replay
|
||||
// the triggering turn's timestamp and arrive with equal updated_at. The
|
||||
// summary_change snapshot still carries a stale whole-chat summary from
|
||||
// when the turn finished.
|
||||
const watchedChat = makeChat("chat-1", {
|
||||
summary: null,
|
||||
last_turn_summary: "New turn",
|
||||
updated_at: "2025-01-01T00:00:00.000Z",
|
||||
});
|
||||
|
||||
const merged = mergeWatchedChatSummary(cachedChat, watchedChat, {
|
||||
eventKind: "summary_change",
|
||||
});
|
||||
expect(merged.last_turn_summary).toBe("New turn");
|
||||
expect(merged.summary).toBe("Whole-chat summary.");
|
||||
});
|
||||
|
||||
it("does not clobber last_turn_summary on a chat_summary_change with equal updated_at", () => {
|
||||
const cachedChat = makeChat("chat-1", {
|
||||
summary: null,
|
||||
last_turn_summary: "Latest turn",
|
||||
updated_at: "2025-01-01T00:00:00.000Z",
|
||||
});
|
||||
const watchedChat = makeChat("chat-1", {
|
||||
summary: "Implemented the whole-chat summary feature.",
|
||||
last_turn_summary: "Stale turn",
|
||||
updated_at: "2025-01-01T00:00:00.000Z",
|
||||
});
|
||||
|
||||
const merged = mergeWatchedChatSummary(cachedChat, watchedChat, {
|
||||
eventKind: "chat_summary_change",
|
||||
});
|
||||
expect(merged.summary).toBe("Implemented the whole-chat summary feature.");
|
||||
expect(merged.last_turn_summary).toBe("Latest turn");
|
||||
});
|
||||
|
||||
it("clears last_turn_summary on summary updates with matching updated_at", () => {
|
||||
const cachedChat = makeChat("chat-1", {
|
||||
last_turn_summary: "Previous summary",
|
||||
|
||||
@@ -420,6 +420,7 @@ export const mergeWatchedChatSummary = (
|
||||
const isTitleEvent = eventKind === "title_change";
|
||||
const isStatusEvent = eventKind === "status_change";
|
||||
const isSummaryEvent = eventKind === "summary_change";
|
||||
const isChatSummaryEvent = eventKind === "chat_summary_change";
|
||||
const isDiffStatusEvent = eventKind === "diff_status_change";
|
||||
const isContextDirtyEvent = eventKind === "context_dirty";
|
||||
const updatedAtComparison = compareUpdatedAtInstants(
|
||||
@@ -456,10 +457,17 @@ export const mergeWatchedChatSummary = (
|
||||
const nextLastModelConfigId = isFreshEnough
|
||||
? watchedChat.last_model_config_id
|
||||
: cachedChat.last_model_config_id;
|
||||
const nextLastTurnSummary =
|
||||
isFreshEnough || isSummaryEvent
|
||||
? watchedChat.last_turn_summary
|
||||
: cachedChat.last_turn_summary;
|
||||
// The summary writes (UpdateChatLastTurnSummary, UpdateChatSummary) never
|
||||
// bump chats.updated_at, and both events publish pre-write chat snapshots,
|
||||
// so updated_at cannot order summary_change against chat_summary_change and
|
||||
// isFreshEnough cannot guard these fields. Scope each field to its own
|
||||
// event, else one event's stale snapshot clobbers the other field's value.
|
||||
const nextLastTurnSummary = isSummaryEvent
|
||||
? watchedChat.last_turn_summary
|
||||
: cachedChat.last_turn_summary;
|
||||
const nextSummary = isChatSummaryEvent
|
||||
? watchedChat.summary
|
||||
: cachedChat.summary;
|
||||
const nextHasUnread =
|
||||
isFreshEnough && isStatusEvent && watchedChat.id !== activeChatId
|
||||
? true
|
||||
@@ -478,6 +486,7 @@ export const mergeWatchedChatSummary = (
|
||||
nextBuildId === cachedChat.build_id &&
|
||||
nextLastModelConfigId === cachedChat.last_model_config_id &&
|
||||
nextLastTurnSummary === cachedChat.last_turn_summary &&
|
||||
nextSummary === cachedChat.summary &&
|
||||
nextHasUnread === cachedChat.has_unread &&
|
||||
nextUpdatedAt === cachedChat.updated_at &&
|
||||
nextContext === cachedChat.context
|
||||
@@ -494,6 +503,7 @@ export const mergeWatchedChatSummary = (
|
||||
build_id: nextBuildId,
|
||||
last_model_config_id: nextLastModelConfigId,
|
||||
last_turn_summary: nextLastTurnSummary,
|
||||
summary: nextSummary,
|
||||
has_unread: nextHasUnread,
|
||||
updated_at: nextUpdatedAt,
|
||||
context: nextContext,
|
||||
|
||||
Generated
+7
@@ -1679,6 +1679,11 @@ export interface Chat {
|
||||
readonly plan_mode?: ChatPlanMode;
|
||||
readonly last_error?: ChatError;
|
||||
readonly last_turn_summary: string | null;
|
||||
/**
|
||||
* Summary is the persisted whole-chat summary, generated in the background.
|
||||
* It is nil until the first summary has been produced.
|
||||
*/
|
||||
readonly summary: string | null;
|
||||
readonly diff_status?: ChatDiffStatus;
|
||||
readonly created_at: string;
|
||||
readonly updated_at: string;
|
||||
@@ -3434,6 +3439,7 @@ export interface ChatWatchEvent {
|
||||
// From codersdk/chats.go
|
||||
export type ChatWatchEventKind =
|
||||
| "action_required"
|
||||
| "chat_summary_change"
|
||||
| "context_dirty"
|
||||
| "created"
|
||||
| "deleted"
|
||||
@@ -3444,6 +3450,7 @@ export type ChatWatchEventKind =
|
||||
|
||||
export const ChatWatchEventKinds: ChatWatchEventKind[] = [
|
||||
"action_required",
|
||||
"chat_summary_change",
|
||||
"context_dirty",
|
||||
"created",
|
||||
"deleted",
|
||||
|
||||
@@ -152,6 +152,7 @@ const baseChatFields = {
|
||||
has_unread: false,
|
||||
client_type: "ui",
|
||||
last_turn_summary: null,
|
||||
summary: null,
|
||||
children: [],
|
||||
} as const;
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ export const WithParentChat: Story = {
|
||||
title: "Set up CI/CD pipeline",
|
||||
status: "waiting",
|
||||
last_turn_summary: null,
|
||||
summary: null,
|
||||
created_at: "2026-02-18T00:00:00.000Z",
|
||||
updated_at: "2026-02-18T00:00:00.000Z",
|
||||
archived: false,
|
||||
|
||||
@@ -29,6 +29,7 @@ const mockChat: Chat = {
|
||||
mcp_server_ids: [],
|
||||
labels: {},
|
||||
last_turn_summary: "Added migration script",
|
||||
summary: "Investigated and fixed a race condition in the auth middleware.",
|
||||
created_at: "2026-05-20T05:00:00.000Z",
|
||||
updated_at: "2026-05-20T07:30:00.000Z",
|
||||
archived: false,
|
||||
|
||||
@@ -20,6 +20,7 @@ export const MockChat: Chat = {
|
||||
title: "Agent",
|
||||
status: "waiting",
|
||||
last_turn_summary: null,
|
||||
summary: null,
|
||||
created_at: MOCK_TIMESTAMP,
|
||||
updated_at: MOCK_TIMESTAMP,
|
||||
archived: false,
|
||||
|
||||
Reference in New Issue
Block a user