mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
fac3158c2a
## Summary Add a server-owned `recencyAt` timestamp and `recency_at` thread-list sort key for product recency ordering while preserving the existing meaning of `updatedAt` as the latest persisted thread mutation. This is the server-side alternative to #27697. Rather than narrowing `updatedAt`, clients can sort the sidebar by `recency_at` and continue treating `updatedAt` as mutation time. Paired Codex Apps PR: [openai/openai#1024599](https://github.com/openai/openai/pull/1024599) ## Contract - `recencyAt` initializes when a thread is created. - A turn start advances `recencyAt` monotonically. - Commentary, agent output, tool results, token/accounting updates, turn completion, archive, unarchive, resume, and generic metadata writes do not advance it. - `updatedAt` retains its existing behavior and continues to advance for persisted thread mutations. - Current servers populate `recencyAt`; the response field is optional in generated TypeScript so clients connected to older servers can fall back to `updatedAt`. - Filesystem-only fallback uses existing updated/mtime ordering when SQLite is unavailable. ## Persistence and compatibility Migration 0038 adds second- and millisecond-precision recency columns, backfills them from the existing updated timestamp, creates list indexes, and includes an insert trigger so older binaries writing to a migrated database seed recency without causing later mutations to advance it. Generic metadata upserts preserve existing recency values. Turn-start updates use a dedicated monotonic touch, and process-local allocation keeps millisecond cursor values unique. State DB list, search, read, filtered-list repair, rollout fallback propagation, and app-server conversions all carry the new field. ## API `Thread` responses include: ```ts recencyAt?: number ``` `thread/list` and `thread/search` accept: ```json { "sortKey": "recency_at" } ``` Generated TypeScript and JSON schemas are included. ## Validation - `just test -p codex-state` — 146 passed - `just test -p codex-rollout` — 69 passed - `just test -p codex-thread-store` — 81 passed - `just test -p codex-app-server-protocol` — 231 passed - Focused app-server list ordering, response mapping, archive/unarchive, and resume lifecycle tests passed - Scoped `just fix` for state, rollout, thread-store, app-server-protocol, and app-server - `just fmt` - `git diff --check` - Independent correctness, simplicity, elegance, security, and test-quality reviews; actionable ordering, lifecycle, query-projection, and timestamp-uniqueness findings were addressed
139 lines
3.3 KiB
JSON
Generated
139 lines
3.3 KiB
JSON
Generated
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"definitions": {
|
|
"SortDirection": {
|
|
"enum": [
|
|
"asc",
|
|
"desc"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"ThreadListCwdFilter": {
|
|
"anyOf": [
|
|
{
|
|
"type": "string"
|
|
},
|
|
{
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": "array"
|
|
}
|
|
]
|
|
},
|
|
"ThreadSortKey": {
|
|
"enum": [
|
|
"created_at",
|
|
"updated_at",
|
|
"recency_at"
|
|
],
|
|
"type": "string"
|
|
},
|
|
"ThreadSourceKind": {
|
|
"enum": [
|
|
"cli",
|
|
"vscode",
|
|
"exec",
|
|
"appServer",
|
|
"subAgent",
|
|
"subAgentReview",
|
|
"subAgentCompact",
|
|
"subAgentThreadSpawn",
|
|
"subAgentOther",
|
|
"unknown"
|
|
],
|
|
"type": "string"
|
|
}
|
|
},
|
|
"properties": {
|
|
"archived": {
|
|
"description": "Optional archived filter; when set to true, only archived threads are returned. If false or null, only non-archived threads are returned.",
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"cursor": {
|
|
"description": "Opaque pagination cursor returned by a previous call.",
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"cwd": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/definitions/ThreadListCwdFilter"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"description": "Optional cwd filter or filters; when set, only threads whose session cwd exactly matches one of these paths are returned."
|
|
},
|
|
"limit": {
|
|
"description": "Optional page size; defaults to a reasonable server-side value.",
|
|
"format": "uint32",
|
|
"minimum": 0.0,
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
]
|
|
},
|
|
"modelProviders": {
|
|
"description": "Optional provider filter; when set, only sessions recorded under these providers are returned. When present but empty, includes all providers.",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"searchTerm": {
|
|
"description": "Optional substring filter for the extracted thread title.",
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"sortDirection": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/definitions/SortDirection"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"description": "Optional sort direction; defaults to descending (newest first)."
|
|
},
|
|
"sortKey": {
|
|
"anyOf": [
|
|
{
|
|
"$ref": "#/definitions/ThreadSortKey"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
],
|
|
"description": "Optional sort key; defaults to created_at."
|
|
},
|
|
"sourceKinds": {
|
|
"description": "Optional source filter; when set, only sessions from these source kinds are returned. When omitted or empty, defaults to interactive sources.",
|
|
"items": {
|
|
"$ref": "#/definitions/ThreadSourceKind"
|
|
},
|
|
"type": [
|
|
"array",
|
|
"null"
|
|
]
|
|
},
|
|
"useStateDbOnly": {
|
|
"description": "If true, return from the state DB without scanning JSONL rollouts to repair thread metadata. Omitted or false preserves scan-and-repair behavior.",
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"title": "ThreadListParams",
|
|
"type": "object"
|
|
} |