Skip to content

Commit 1cd581f

Browse files
TweedBeetlemjacobs
andauthored
parser: capture sessionKind and promptSource from Claude Code transcripts (#1253)
## What Capture two Claude Code launch/prompt-provenance fields that the indexer currently reads past and discards: - **`sessionKind`** — session-level (e.g. `"bg"`). Present on background/headless sessions, absent on interactive ones. Lands in a new `session_kind` column on `sessions`. - **`promptSource`** — per user turn (e.g. `"typed"`, `"queued"`, `"system"`, `"sdk"`). Marks whether a turn was a human-typed prompt or a queued/system/SDK-injected one. Lands in a new `prompt_source` column on `messages`. ## Why Both signals exist on essentially every current Claude Code transcript but are thrown away at parse time, so the archive can't answer two questions it otherwise has the data for: was a session interactive or headless, and was a given prompt typed by a human or injected. This mirrors the recently-added `entrypoint` capture — same shape of information, same reason to keep it. ## How The change follows the existing `entrypoint` / `agent_label` and `source_type` / `is_sidechain` handling rather than inventing a new pattern: - `sessionKind` is treated as a session-identity field alongside `entrypoint`: first-non-empty-wins across the file, wired into the incremental identity-escalation check, and blanked by the Cowork and Qoder parsers that reuse the Claude parse body (exactly as they blank `entrypoint`). - `promptSource` is treated as a per-message source column alongside `source_type`/`is_sidechain`, including the retained-field whitelist in `compactClaudeEntry` and the message token fingerprints the PG/DuckDB push fast-paths compare against. Both columns are `NOT NULL DEFAULT ''`, so transcripts that predate the fields and other agents that never emit them read empty and are otherwise untouched. A `dataVersion` bump (79) triggers the standard reparse so existing Claude rows backfill both fields. Capture is mirrored across the SQLite, Postgres, and DuckDB stores (mirror `SchemaVersion` 9) and the artifact wire format, where the manifest advances to v3 and message segments to v2: older artifacts still decode with the fields empty, while pre-provenance peers park new artifacts behind the existing future-version gate instead of silently dropping the fields. The fields also round-trip through artifact import, re-enqueue a published session's export when only `session_kind` changes, and count toward the export preflight's message-byte bound. ## Scope / limitations - Pure field capture — no counting, aggregation, health-signal, or automation-classification logic is touched. - `session_kind`/`prompt_source` backfill via the dataVersion-79 reparse; rows whose source files no longer exist stay empty. - No new API/CLI surface or UI is added; the columns are available for consumers that read the archive directly. ## Where to look - `internal/parser/claude.go` — the capture site (`sessionKind` next to `entrypoint`; `promptSource` next to `isSidechain`) and the `compactClaudeEntry` retained-field whitelist. - `internal/parser/claude_provider.go`, `provider.go`, `internal/sync/engine.go` — incremental identity threading for `sessionKind`. - `internal/db/{schema.sql,db.go,sessions.go,messages.go}` — SQLite columns, migrations, and read/write plumbing. - `internal/postgres/*` and `internal/duckdb/*` — the mirrored columns and fingerprints. The source of truth for both fields is the Claude Code transcript format, where `sessionKind` and `promptSource` appear as top-level keys on session JSONL entries. --------- Co-authored-by: Matthew Jacobs <mjacobs@apache.org>
1 parent 5bc9617 commit 1cd581f

56 files changed

Lines changed: 635 additions & 146 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/internal/session-format-sources.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ Grok section and remove the explicit registry exception in the coverage test.
103103
in [#1238](https://github.com/kenn-io/agentsview/issues/1238): Claude Code
104104
for VS Code writes standalone `user` records wrapped in `ide_opened_file` or
105105
`ide_selection` tags for editor context rather than operator prompts.
106+
Reverified 2026-07-24 against local CLI transcripts: current
107+
transcripts carry two top-level launch/prompt-provenance keys that the
108+
parser now captures — `sessionKind` (session-level, e.g. `"bg"`; present on
109+
background/headless sessions and absent on interactive ones) and
110+
`promptSource` (per user turn, e.g. `"typed"`, `"queued"`, `"system"`,
111+
`"sdk"`). Neither key is documented upstream or covered by the codeburn
112+
notes; the evidence remains local observation under `no-public-source`.
106113

107114
## OpenClaude (`openclaude`)
108115

frontend/src/lib/api/generated/models/DbMessage.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/lib/api/generated/models/DbSession.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/lib/api/generated/models/DbSidebarSessionIndexRow.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/artifact/format_test.go

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ func TestCanonicalManifestGolden(t *testing.T) {
9797
require.NoError(t, err)
9898

9999
assert.Equal(t,
100-
"{\"data_version\":99,\"generation\":3,\"native_session_id\":\"sess-1\",\"origin\":\"laptop-a1b2c3\",\"raw_source\":{\"hash\":\"raw123\",\"media_type\":\"application/jsonl\",\"path\":\"claude/session.jsonl\",\"size\":4096},\"segments\":[\"seg222\",\"seg111\"],\"session\":{\"agent\":\"claude\",\"compaction_count\":0,\"consecutive_failure_max\":0,\"created_at\":\"2026-06-14T01:02:03Z\",\"edit_churn_count\":0,\"ended_at\":\"2026-06-14T01:03:03Z\",\"ended_with_role\":\"\",\"final_failure_streak\":0,\"first_message\":\"hello\",\"has_peak_context_tokens\":false,\"has_total_output_tokens\":false,\"id\":\"sess-1\",\"is_automated\":false,\"machine\":\"laptop-a1b2c3\",\"message_count\":2,\"mid_task_compaction_count\":0,\"outcome\":\"\",\"outcome_confidence\":\"\",\"parent_session_id\":\"parent-1\",\"peak_context_tokens\":0,\"project\":\"alpha\",\"relationship_type\":\"subagent\",\"secret_leak_count\":0,\"started_at\":\"2026-06-14T01:02:03Z\",\"tool_failure_signal_count\":0,\"tool_retry_count\":0,\"total_output_tokens\":42,\"user_message_count\":1},\"session_has_context_data\":true,\"session_has_tool_calls\":true,\"session_name\":\"Fixture\",\"session_quality_signals\":{\"duplicate_prompt_count\":6,\"missing_success_criteria_count\":4,\"missing_verification_count\":5,\"no_code_context_count\":7,\"runaway_tool_loop_count\":1,\"short_prompt_count\":2,\"unstructured_start\":true,\"version\":3},\"usage_events\":[{\"cost\":{\"microdollars\":31250},\"cost_source\":\"fixture\",\"cost_status\":\"known\",\"dedup_key\":\"usage-1\",\"input_tokens\":11,\"message_ordinal\":2,\"model\":\"claude-test\",\"occurred_at\":\"2026-06-14T01:02:04Z\",\"output_tokens\":7,\"source\":\"fixture\"}],\"v\":2}\n",
100+
"{\"data_version\":99,\"generation\":3,\"native_session_id\":\"sess-1\",\"origin\":\"laptop-a1b2c3\",\"raw_source\":{\"hash\":\"raw123\",\"media_type\":\"application/jsonl\",\"path\":\"claude/session.jsonl\",\"size\":4096},\"segments\":[\"seg222\",\"seg111\"],\"session\":{\"agent\":\"claude\",\"compaction_count\":0,\"consecutive_failure_max\":0,\"created_at\":\"2026-06-14T01:02:03Z\",\"edit_churn_count\":0,\"ended_at\":\"2026-06-14T01:03:03Z\",\"ended_with_role\":\"\",\"final_failure_streak\":0,\"first_message\":\"hello\",\"has_peak_context_tokens\":false,\"has_total_output_tokens\":false,\"id\":\"sess-1\",\"is_automated\":false,\"machine\":\"laptop-a1b2c3\",\"message_count\":2,\"mid_task_compaction_count\":0,\"outcome\":\"\",\"outcome_confidence\":\"\",\"parent_session_id\":\"parent-1\",\"peak_context_tokens\":0,\"project\":\"alpha\",\"relationship_type\":\"subagent\",\"secret_leak_count\":0,\"started_at\":\"2026-06-14T01:02:03Z\",\"tool_failure_signal_count\":0,\"tool_retry_count\":0,\"total_output_tokens\":42,\"user_message_count\":1},\"session_has_context_data\":true,\"session_has_tool_calls\":true,\"session_name\":\"Fixture\",\"session_quality_signals\":{\"duplicate_prompt_count\":6,\"missing_success_criteria_count\":4,\"missing_verification_count\":5,\"no_code_context_count\":7,\"runaway_tool_loop_count\":1,\"short_prompt_count\":2,\"unstructured_start\":true,\"version\":3},\"usage_events\":[{\"cost\":{\"microdollars\":31250},\"cost_source\":\"fixture\",\"cost_status\":\"known\",\"dedup_key\":\"usage-1\",\"input_tokens\":11,\"message_ordinal\":2,\"model\":\"claude-test\",\"occurred_at\":\"2026-06-14T01:02:04Z\",\"output_tokens\":7,\"source\":\"fixture\"}],\"v\":3}\n",
101101
string(data),
102102
)
103-
assert.Equal(t, "d84a3987c40f800f23ea943ebd50c0910c64444e6ff4b64b6f8a68782f7a32d6", hashHex(data))
103+
assert.Equal(t, "855d1a7ed086095582cc94136837bcb93d74f4ad0cf446b0a77177d1b31aba23", hashHex(data))
104104
}
105105

106106
func TestDecodeManifestRejectsUnsupportedOlderVersion(t *testing.T) {
@@ -122,6 +122,37 @@ func TestDecodeManifestRejectsUnsupportedOlderVersion(t *testing.T) {
122122
assert.Contains(t, err.Error(), "manifest has unsupported artifact version 1")
123123
}
124124

125+
func TestDecodeManifestAcceptsPriorVersionWithoutSessionKind(t *testing.T) {
126+
data := []byte(`{
127+
"v": 2,
128+
"origin": "laptop-a1b2c3",
129+
"native_session_id": "sess-1",
130+
"segments": [],
131+
"session": {
132+
"id": "sess-1",
133+
"machine": "laptop-a1b2c3",
134+
"agent": "claude",
135+
"created_at": "2026-06-14T01:02:03Z"
136+
}
137+
}`)
138+
139+
decoded, err := decodeManifestWithLimits(data, productionArtifactLimits())
140+
require.NoError(t, err)
141+
assert.Equal(t, 2, decoded.Version)
142+
assert.Empty(t, decoded.Session.SessionKind,
143+
"v2 manifests predate session_kind and must decode with it empty")
144+
}
145+
146+
func TestDecodeSegmentAcceptsPriorVersionWithoutPromptSource(t *testing.T) {
147+
data := []byte("{\"content\":\"hello\",\"ordinal\":0,\"role\":\"user\",\"v\":1}\n")
148+
149+
msgs, err := decodeSegmentWithLimits(data, productionArtifactLimits())
150+
require.NoError(t, err)
151+
require.Len(t, msgs, 1)
152+
assert.Empty(t, msgs[0].PromptSource,
153+
"v1 segments predate prompt_source and must decode with it empty")
154+
}
155+
125156
func TestCanonicalMessageSegmentGolden(t *testing.T) {
126157
msgs := []db.Message{
127158
{
@@ -177,13 +208,39 @@ func TestCanonicalMessageSegmentGolden(t *testing.T) {
177208
require.NoError(t, err)
178209

179210
assert.Equal(t,
180-
"{\"claude_message_id\":\"msg-1\",\"claude_request_id\":\"req-1\",\"content\":\"world\",\"content_length\":5,\"has_output_tokens\":true,\"has_tool_use\":true,\"model\":\"claude-test\",\"ordinal\":2,\"output_tokens\":2,\"role\":\"assistant\",\"source_parent_uuid\":\"uuid-parent\",\"source_subtype\":\"assistant\",\"source_type\":\"jsonl\",\"source_uuid\":\"uuid-msg-1\",\"timestamp\":\"2026-06-14T01:02:05Z\",\"token_usage\":{\"input\":1,\"output\":2},\"tool_calls\":[{\"call_index\":0,\"category\":\"file\",\"file_path\":\"README.md\",\"input_json\":\"{\\\"file_path\\\":\\\"README.md\\\"}\",\"result_content\":\"file content\",\"result_content_length\":12,\"result_events\":[{\"agent_id\":\"agent-1\",\"content\":\"done\",\"content_length\":4,\"event_index\":0,\"source\":\"tool_result\",\"status\":\"success\",\"subagent_session_id\":\"child-1\",\"timestamp\":\"2026-06-14T01:02:06Z\",\"tool_use_id\":\"tool-1\"}],\"subagent_session_id\":\"child-1\",\"tool_name\":\"Read\",\"tool_use_id\":\"tool-1\"}],\"v\":1}\n",
211+
"{\"claude_message_id\":\"msg-1\",\"claude_request_id\":\"req-1\",\"content\":\"world\",\"content_length\":5,\"has_output_tokens\":true,\"has_tool_use\":true,\"model\":\"claude-test\",\"ordinal\":2,\"output_tokens\":2,\"role\":\"assistant\",\"source_parent_uuid\":\"uuid-parent\",\"source_subtype\":\"assistant\",\"source_type\":\"jsonl\",\"source_uuid\":\"uuid-msg-1\",\"timestamp\":\"2026-06-14T01:02:05Z\",\"token_usage\":{\"input\":1,\"output\":2},\"tool_calls\":[{\"call_index\":0,\"category\":\"file\",\"file_path\":\"README.md\",\"input_json\":\"{\\\"file_path\\\":\\\"README.md\\\"}\",\"result_content\":\"file content\",\"result_content_length\":12,\"result_events\":[{\"agent_id\":\"agent-1\",\"content\":\"done\",\"content_length\":4,\"event_index\":0,\"source\":\"tool_result\",\"status\":\"success\",\"subagent_session_id\":\"child-1\",\"timestamp\":\"2026-06-14T01:02:06Z\",\"tool_use_id\":\"tool-1\"}],\"subagent_session_id\":\"child-1\",\"tool_name\":\"Read\",\"tool_use_id\":\"tool-1\"}],\"v\":2}\n",
181212
string(data),
182213
)
183214
assert.NotContains(t, string(data), `"id"`)
184215
assert.NotContains(t, string(data), `"session_id"`)
185216
assert.NotContains(t, string(data), `"message_id"`)
186-
assert.Equal(t, "f46c1edbc77dab4eb15f43bcb3ce196243c784445b07e9135c223b5d58c6dea5", hashHex(data))
217+
assert.Equal(t, "e45219604ab58bb9685ac3dfb0f5cc5e865705e29dc8a985ccebe1b748a6d396", hashHex(data))
218+
}
219+
220+
func TestEncodeSegmentPreservesPromptSource(t *testing.T) {
221+
msgs := []db.Message{
222+
{
223+
ID: 1,
224+
SessionID: "sess-1",
225+
Ordinal: 1,
226+
Role: "user",
227+
Content: "hello",
228+
SourceType: "jsonl",
229+
SourceSubtype: "user",
230+
PromptSource: "typed",
231+
},
232+
}
233+
234+
data, err := encodeSegment(msgs)
235+
require.NoError(t, err)
236+
237+
var decoded segmentMessage
238+
require.NoError(t, json.Unmarshal(data, &decoded))
239+
assert.Equal(t, "typed", decoded.PromptSource)
240+
241+
restored := decoded.dbMessage()
242+
assert.Equal(t, "typed", restored.PromptSource,
243+
"import must carry prompt_source back into the db message")
187244
}
188245

189246
func TestCanonicalMetadataEventGolden(t *testing.T) {

internal/artifact/import_checkpoint_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,34 +72,34 @@ func TestReadVerifiedImportArtifactByteBoundaries(t *testing.T) {
7272
func TestFutureArtifactVersionErrorsIdentifyDependencyKind(t *testing.T) {
7373
t.Run("manifest", func(t *testing.T) {
7474
_, err := decodeManifestWithLimits(
75-
[]byte(`{"origin":"contract-a1b2c3","v":3}`),
75+
[]byte(`{"origin":"contract-a1b2c3","v":4}`),
7676
productionArtifactLimits(),
7777
)
7878
require.ErrorIs(t, err, errFutureArtifactVersion)
7979
var future *futureArtifactVersionError
8080
require.ErrorAs(t, err, &future)
8181
assert.Equal(t, Kind(KindManifests), future.Kind)
82-
assert.Equal(t, 3, future.Version)
82+
assert.Equal(t, 4, future.Version)
8383
})
8484

8585
t.Run("segment", func(t *testing.T) {
8686
_, err := decodeSegmentWithLimits(
87-
[]byte("{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":2}\n"),
87+
[]byte("{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":3}\n"),
8888
productionArtifactLimits(),
8989
)
9090
require.ErrorIs(t, err, errFutureArtifactVersion)
9191
var future *futureArtifactVersionError
9292
require.ErrorAs(t, err, &future)
9393
assert.Equal(t, Kind(KindSegments), future.Kind)
94-
assert.Equal(t, 2, future.Version)
94+
assert.Equal(t, 3, future.Version)
9595
})
9696
}
9797

9898
func TestFutureSegmentVersionPrecedesCurrentRecordLimit(t *testing.T) {
9999
var body strings.Builder
100100
for range productionArtifactLimits().segmentMessages + 1 {
101101
body.WriteString(
102-
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":2}\n",
102+
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":3}\n",
103103
)
104104
}
105105

@@ -110,7 +110,7 @@ func TestFutureSegmentVersionPrecedesCurrentRecordLimit(t *testing.T) {
110110
var future *futureArtifactVersionError
111111
require.ErrorAs(t, err, &future)
112112
assert.Equal(t, Kind(KindSegments), future.Kind)
113-
assert.Equal(t, 2, future.Version)
113+
assert.Equal(t, 3, future.Version)
114114
}
115115

116116
func TestCurrentSegmentRecordLimitPrecedesLaterRecordDecode(t *testing.T) {

internal/artifact/import_session.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func loadImportedSession(
159159
func validateImportedManifest(
160160
m manifest, origin, gid string, limits artifactLimits,
161161
) error {
162-
if m.Version != manifestFormatVersion {
162+
if m.Version < manifestMinDecodeVersion || m.Version > manifestFormatVersion {
163163
return errors.New("manifest version is unsupported")
164164
}
165165
if m.Origin != origin {

internal/artifact/import_session_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func TestLoadImportedSessionDefersOversizedFutureSegment(t *testing.T) {
143143
var segment strings.Builder
144144
for range productionArtifactLimits().segmentMessages + 1 {
145145
segment.WriteString(
146-
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":2}\n",
146+
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":3}\n",
147147
)
148148
}
149149
segmentHash := createHashedImportArtifact(
@@ -165,7 +165,7 @@ func TestLoadImportedSessionDefersOversizedFutureSegment(t *testing.T) {
165165
var future *futureArtifactVersionError
166166
require.ErrorAs(t, err, &future)
167167
assert.Equal(t, Kind(KindSegments), future.Kind)
168-
assert.Equal(t, 2, future.Version)
168+
assert.Equal(t, 3, future.Version)
169169
}
170170

171171
func TestLoadImportedSessionDefersMissingAndFutureDependencies(t *testing.T) {
@@ -191,7 +191,7 @@ func TestLoadImportedSessionDefersMissingAndFutureDependencies(t *testing.T) {
191191
{
192192
name: "future manifest",
193193
prepare: func(t *testing.T, store ArtifactStore) string {
194-
body := []byte(`{"origin":"contract-a1b2c3","v":3}`)
194+
body := []byte(`{"origin":"contract-a1b2c3","v":4}`)
195195
return createHashedImportArtifact(
196196
t, store, KindManifests, ".json", body,
197197
)
@@ -202,7 +202,7 @@ func TestLoadImportedSessionDefersMissingAndFutureDependencies(t *testing.T) {
202202
name: "future segment",
203203
prepare: func(t *testing.T, store ArtifactStore) string {
204204
segment := []byte(
205-
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":2}\n",
205+
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":3}\n",
206206
)
207207
segmentHash := createHashedImportArtifact(
208208
t, store, KindSegments, ".ndjson", segment,

internal/artifact/import_test.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,21 +217,22 @@ func TestStoreImportCoordinatorTracksIndependentFutureRequirements(t *testing.T)
217217
prepare: func(t *testing.T, store ArtifactStore) string {
218218
return createHashedImportArtifact(
219219
t, store, KindManifests, ".json",
220-
[]byte(`{"origin":"contract-a1b2c3","v":3}`),
220+
[]byte(`{"origin":"contract-a1b2c3","v":4}`),
221221
)
222222
},
223-
wantManifest: 3, wantSegment: messageSegmentFormatVersion,
223+
wantManifest: manifestFormatVersion + 1,
224+
wantSegment: messageSegmentFormatVersion,
224225
understood: db.ArtifactImportVersions{
225226
Checkpoint: checkpointFormatVersion,
226-
Manifest: 3,
227+
Manifest: manifestFormatVersion + 1,
227228
Segment: messageSegmentFormatVersion,
228229
},
229230
},
230231
{
231232
name: "future segment",
232233
prepare: func(t *testing.T, store ArtifactStore) string {
233234
segment := []byte(
234-
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":2}\n",
235+
"{\"content\":\"future\",\"ordinal\":0,\"role\":\"user\",\"v\":3}\n",
235236
)
236237
segmentHash := createHashedImportArtifact(
237238
t, store, KindSegments, ".ndjson", segment,
@@ -240,11 +241,12 @@ func TestStoreImportCoordinatorTracksIndependentFutureRequirements(t *testing.T)
240241
m.Segments = []string{segmentHash}
241242
return createImportTestManifest(t, store, m, false)
242243
},
243-
wantManifest: manifestFormatVersion, wantSegment: 2,
244+
wantManifest: manifestFormatVersion,
245+
wantSegment: messageSegmentFormatVersion + 1,
244246
understood: db.ArtifactImportVersions{
245247
Checkpoint: checkpointFormatVersion,
246248
Manifest: manifestFormatVersion,
247-
Segment: 2,
249+
Segment: messageSegmentFormatVersion + 1,
248250
},
249251
},
250252
}
@@ -343,7 +345,7 @@ func TestStoreImportCoordinatorFinishesSupportedSessionsBeforeFutureGate(
343345
sessionMap := map[string]string{
344346
contractOrigin + "~000-future": createHashedImportArtifact(
345347
t, store, KindManifests, ".json",
346-
[]byte(`{"origin":"contract-a1b2c3","v":3}`),
348+
[]byte(`{"origin":"contract-a1b2c3","v":4}`),
347349
),
348350
}
349351
const supportedSessions = artifactImportDrainLimit + 1
@@ -405,15 +407,15 @@ func TestStoreImportCoordinatorFinishesSupportedSessionsBeforeFutureGate(
405407
t.Context(),
406408
db.ArtifactImportVersions{
407409
Checkpoint: checkpointFormatVersion,
408-
Manifest: 3,
410+
Manifest: manifestFormatVersion + 1,
409411
Segment: messageSegmentFormatVersion,
410412
},
411413
attempt,
412414
10,
413415
)
414416
require.NoError(t, err)
415417
require.Len(t, pending, 1)
416-
assert.Equal(t, 3, pending[0].RequiredManifestVersion)
418+
assert.Equal(t, manifestFormatVersion+1, pending[0].RequiredManifestVersion)
417419
}
418420

419421
func TestStoreImportCoordinatorQuarantinesInvalidCheckpointAndContinues(

internal/artifact/manifest_session.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type manifestSession struct {
1616
Agent string `json:"agent"`
1717
AgentLabel string `json:"agent_label,omitempty"`
1818
Entrypoint string `json:"entrypoint,omitempty"`
19+
SessionKind string `json:"session_kind,omitempty"`
1920
FirstMessage *string `json:"first_message"`
2021
DisplayName *string `json:"display_name,omitempty"`
2122
StartedAt *string `json:"started_at"`
@@ -95,6 +96,7 @@ func manifestSessionFromDB(s db.Session) manifestSession {
9596
Agent: s.Agent,
9697
AgentLabel: s.AgentLabel,
9798
Entrypoint: s.Entrypoint,
99+
SessionKind: s.SessionKind,
98100
FirstMessage: s.FirstMessage,
99101
DisplayName: s.DisplayName,
100102
StartedAt: s.StartedAt,
@@ -155,6 +157,7 @@ func (m manifestSession) dbSession() db.Session {
155157
Agent: m.Agent,
156158
AgentLabel: m.AgentLabel,
157159
Entrypoint: m.Entrypoint,
160+
SessionKind: m.SessionKind,
158161
FirstMessage: m.FirstMessage,
159162
DisplayName: m.DisplayName,
160163
StartedAt: m.StartedAt,

0 commit comments

Comments
 (0)