mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add last_injected_context column to chats table (#23798)
Adds a nullable JSONB column `last_injected_context` to the `chats` table that stores the most recently persisted injected context parts (AGENTS.md context-file and skill message parts). The column is updated only when `persistInstructionFiles()` runs — on first workspace attach or when the agent changes — so there are no redundant writes on subsequent turns. Internal fields (`ContextFileContent`, `ContextFileOS`, `ContextFileDirectory`, `SkillDir`) are stripped at write time so the column only holds small metadata. No stripping needed on the read path. <details> <summary>Implementation notes</summary> - New migration `000456` adds nullable `last_injected_context JSONB` column. - New SQL query `UpdateChatLastInjectedContext` writes the column without touching `updated_at`. - `persistInstructionFiles()` strips internal fields from parts via `StripInternal()` before persisting. - Sentinel path (no AGENTS.md) persists skill-only parts when skills exist. - `codersdk.Chat` exposes `LastInjectedContext []ChatMessagePart` (omitempty). - `db2sdk.Chat()` passes through the already-clean data. </details>
This commit is contained in:
@@ -1572,6 +1572,17 @@ func Chat(c database.Chat, diffStatus *database.ChatDiffStatus) codersdk.Chat {
|
||||
convertedDiffStatus := ChatDiffStatus(c.ID, diffStatus)
|
||||
chat.DiffStatus = &convertedDiffStatus
|
||||
}
|
||||
if c.LastInjectedContext.Valid {
|
||||
var parts []codersdk.ChatMessagePart
|
||||
// Internal fields are stripped at write time in
|
||||
// chatd.updateLastInjectedContext, so no
|
||||
// StripInternal call is needed here. Unmarshal
|
||||
// errors are suppressed — the column is written by
|
||||
// us with a known schema.
|
||||
if err := json.Unmarshal(c.LastInjectedContext.RawMessage, &parts); err == nil {
|
||||
chat.LastInjectedContext = parts
|
||||
}
|
||||
}
|
||||
return chat
|
||||
}
|
||||
|
||||
|
||||
@@ -541,6 +541,13 @@ func TestChat_AllFieldsPopulated(t *testing.T) {
|
||||
PinOrder: 1,
|
||||
MCPServerIDs: []uuid.UUID{uuid.New()},
|
||||
Labels: database.StringMap{"env": "prod"},
|
||||
LastInjectedContext: pqtype.NullRawMessage{
|
||||
// Use a context-file part to verify internal
|
||||
// fields are not present (they are stripped at
|
||||
// write time by chatd, not at read time).
|
||||
RawMessage: json.RawMessage(`[{"type":"context-file","context_file_path":"/AGENTS.md"}]`),
|
||||
Valid: true,
|
||||
},
|
||||
}
|
||||
// Only ChatID is needed here. This test checks that
|
||||
// Chat.DiffStatus is non-nil, not that every DiffStatus
|
||||
|
||||
Reference in New Issue
Block a user