Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Generated by Scripts/regenerate-codex-parser-hash.sh. Do not edit by hand.

enum CodexParserHash {
static let value = "3aa49b47f4b78e13"
static let value = "f90ee3aa5b4f84a2"
}
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ extension CostUsageScanner {
from logs
where ts >= ? and ts < ?
and (feedback_log_body like '%websocket request:%'
or feedback_log_body like '%response.completed%')
or feedback_log_body like '%response.completed%'
or feedback_log_body like '%service_tier: Some(Some("priority"))%')
"""
var stmt: OpaquePointer?
guard sqlite3_prepare_v2(db, query, -1, &stmt, nil) == SQLITE_OK else { return [:] }
Expand Down Expand Up @@ -507,7 +508,8 @@ extension CostUsageScanner {
from logs indexed by idx_logs_ts
where ts >= ?
and (feedback_log_body like '%websocket request:%'
or feedback_log_body like '%response.completed%')
or feedback_log_body like '%response.completed%'
or feedback_log_body like '%service_tier: Some(Some("priority"))%')
order by rowid
""",
true)
Expand All @@ -518,7 +520,8 @@ extension CostUsageScanner {
from logs
where rowid > ? and ts >= ?
and (feedback_log_body like '%websocket request:%'
or feedback_log_body like '%response.completed%')
or feedback_log_body like '%response.completed%'
or feedback_log_body like '%service_tier: Some(Some("priority"))%')
order by rowid
""",
false)
Expand All @@ -539,7 +542,9 @@ extension CostUsageScanner {
#endif

static func parseCodexPriorityTraceRow(timestamp: String?, body: String) -> CodexPriorityTurnMetadata? {
guard let markerRange = body.range(of: self.requestMarker) else { return nil }
guard let markerRange = body.range(of: self.requestMarker) else {
return self.parseCodexPrioritySubmissionRow(timestamp: timestamp, body: body)
}
let prefix = String(body[..<markerRange.lowerBound])
let jsonText = body[markerRange.upperBound...].trimmingCharacters(in: .whitespacesAndNewlines)
guard let data = jsonText.data(using: .utf8),
Expand All @@ -560,6 +565,25 @@ extension CostUsageScanner {
timestamp: timestamp)
}

private static func parseCodexPrioritySubmissionRow(
timestamp: String?,
body: String) -> CodexPriorityTurnMetadata?
{
guard body.contains(#"service_tier: Some(Some("priority"))"#),
let submissionRange = body.range(of: "Submission sub=Submission {")
Comment on lines +572 to +573

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict the priority marker to thread settings

When a standard-mode user prompt itself contains service_tier: Some(Some("priority"))—for example, while debugging or pasting a trace—the serialized Submission row includes that text in op: UserInput even though its actual ThreadSettingsOverrides uses the default tier. This whole-body check therefore marks that standard turn as Fast and overstates its cost; inspect the actual thread_settings field rather than accepting the marker anywhere in the prompt-bearing row.

Useful? React with 👍 / 👎.

else { return nil }
let submission = String(body[submissionRange.upperBound...])
guard let turnID = self.quotedValue(named: "id", in: submission) else { return nil }

return CodexPriorityTurnMetadata(
threadID: self.value(
named: "thread_id",
in: String(body[..<submissionRange.lowerBound])),
turnID: turnID,
model: nil,
timestamp: timestamp)
}

static func parseCodexCompletedTraceRow(body: String) -> (turnID: String, model: String)? {
let marker = "websocket event:"
guard let markerRange = body.range(of: marker) else { return nil }
Expand All @@ -584,11 +608,19 @@ extension CostUsageScanner {
guard let range = text.range(of: "\(name)=") else { return nil }
let tail = text[range.upperBound...]
let value = tail.prefix { char in
!char.isWhitespace && char != "," && char != "]" && char != ")"
!char.isWhitespace && char != "," && char != "]" && char != ")" && char != "}" && char != ":"
}
return value.isEmpty ? nil : String(value)
}

private static func quotedValue(named name: String, in text: String) -> String? {
guard let range = text.range(of: "\(name): \"") else { return nil }
let tail = text[range.upperBound...]
guard let end = tail.firstIndex(of: "\"") else { return nil }
let value = tail[..<end]
return value.isEmpty ? nil : String(value)
}

#if canImport(SQLite3)
private static func text(stmt: OpaquePointer?, index: Int32) -> String? {
guard sqlite3_column_type(stmt, index) != SQLITE_NULL,
Expand Down
36 changes: 36 additions & 0 deletions Tests/CodexBarTests/CostUsageScannerCodexPriorityTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ struct CostUsageScannerCodexPriorityTests {
#expect(parsed?.timestamp == "2026-05-10T12:00:00Z")
}

@Test
func `parses current priority submission metadata without exposing prompt`() {
let body = "session_loop{thread_id=thread}: Submission sub=Submission { "
+ "id: \"turn\", op: UserInput { text: \"private\" }, "
+ #"thread_settings: ThreadSettingsOverrides { service_tier: Some(Some("priority")) }"#

let parsed = CostUsageScanner.parseCodexPriorityTraceRow(
timestamp: "1785434553",
body: body)

#expect(parsed?.threadID == "thread")
#expect(parsed?.turnID == "turn")
#expect(parsed?.model == nil)
#expect(parsed?.timestamp == "1785434553")
}

@Test
func `ignores non priority malformed and non response request rows`() {
let prefix = "thread_id=thread turn.id=turn websocket request: "
Expand Down Expand Up @@ -74,6 +90,26 @@ struct CostUsageScannerCodexPriorityTests {
#expect(turns["turn-a"]?.model == "request-model")
}

@Test
func `reads current priority submission rows from sqlite logs table`() throws {
let env = try CostUsageTestEnvironment()
defer { env.cleanup() }
let dbURL = env.root.appendingPathComponent("logs_2.sqlite")
try Self.createTestLogsDatabase(at: dbURL)
try Self.insertTestLog(
dbURL: dbURL,
timestamp: "2026-05-10T12:00:00Z",
body: "session_loop{thread_id=thread}: Submission sub=Submission { "
+ "id: \"turn\", op: UserInput { text: \"private\" }, "
+ #"thread_settings: ThreadSettingsOverrides { service_tier: Some(Some("priority")) }"#)

let turns = CostUsageScanner.codexPriorityTurns(databaseURL: dbURL)

#expect(turns.keys.sorted() == ["turn"])
#expect(turns["turn"]?.threadID == "thread")
#expect(turns["turn"]?.model == nil)
}

@Test
func `cold scan uses timestamp index and warm scan uses rowid cursor`() throws {
let env = try CostUsageTestEnvironment()
Expand Down