feat: report a file's modified time through every listing that can - #104
Merged
Conversation
FileInfo gains an optional modified_at — ISO 8601, UTC — so a consumer listing a workspace can say when a file changed instead of stopping at its size. Downstream, vstorm-co/agenticos#500 is the file viewer header that has nowhere to get one today. Filled where a real timestamp exists, absent where none does: - StateBackend: FileData already records modified_at on every write; the listing now surfaces it. A document persisted before the key existed lists None rather than inventing a time. - LocalBackend: st_mtime, on ls and glob. A directory entry carries None — its mtime says when the directory changed, not any file. - Stored workspace archives (sandboxd): st_mtime through the wire. wire.FileEntry.modified_at defaults to None, so a client and a service on either side of this release keep understanding each other; a row from an older service validates to None. - KubernetesPodSandbox (http mode): read from the in-pod server's row when it sends one; the server ships with the user's image, so an older one simply does not. - Shell-derived listings (docker/daytona exec) stay absent: ls -la output has no timestamp that survives locale, busybox and timezone, and a guessed time is worse than none. 1670 tests, 100% coverage, ruff/pyright/mypy clean.
Merged
DEENUU1
added a commit
that referenced
this pull request
Aug 16, 2026
Cuts 0.2.26 for #104 — `FileInfo.modified_at`, an optional ISO 8601 timestamp on every listing that has a real one to give. Additive: the key is optional and `wire.FileEntry` defaults it to `None`, so a client and a service on either side of the release keep understanding each other. Version and changelog only. Verified on #104 before merge: 1670 tests, 100% coverage, ruff/pyright/mypy clean.
DEENUU1
added a commit
to vstorm-co/agenticos
that referenced
this pull request
Aug 16, 2026
The shared file viewer's header reads `MD · 3 B · modified 2 minutes ago` — and the third part only ever appeared for a knowledge base document. A workspace file, which is most of what people open, stopped at the size. Not a viewer bug: `ViewerFile.modifiedAt` existed and the header rendered it; the listing simply had no time to give. **Upstream first.** `pydantic-ai-backend` 0.2.26 ([vstorm-co/pydantic-ai-backend#104](vstorm-co/pydantic-ai-backend#104), released) adds `FileInfo.modified_at` (ISO 8601, optional), filled where a real timestamp exists: a stored workspace records one on every write inside its JSONB document, a workspace archive reports `st_mtime` through the wire, and a live container's shell listing honestly reports none — `null` is the answer there, never a guess. `wire.FileEntry.modified_at` defaults to `None`, so a client and a sandboxd on either side of the release keep understanding each other. **This PR carries it through:** - Bumps the pin to `>=0.2.26`. - `WorkspaceFileRead` (and `FlatFileRead` through it) gains `modified_at: datetime | None` — the flat all-files listing gets the field now because #138 sorts on it. - The three listing routes pass `entry.get("modified_at")` through. - `WorkspaceFile` / `ConversationFile` carry it into `ViewerFile.modifiedAt` in the chat panel, the workspace explorer and the flat browser. **Verified:** - An integration test proves the timestamp survives the JSONB round trip through Postgres for a `state` workspace — the backend every deployment has. - An API test proves a row carrying a time serializes it and a legacy row serializes `null`. - A panel test proves the header now says `modified …` for a file the agent wrote, opened from the chat panel. - `make check` green (lint, backend 5281 tests at 100% platform coverage, frontend gate, db-check, builds, audit). No docs page describes listing rows field by field; the schema docstring carries the reasoning. Closes #500
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FileInfogains an optionalmodified_at(ISO 8601, UTC), so a listing can say when a file changed instead of stopping at its size. The consumer that needs it is vstorm-co/agenticos#500 — the shared file viewer's header readsMD · 3 B · modified 2 minutes agofor a knowledge-base document and stops at the size for a workspace file, because this library's listings had no time to give.Filled where a real timestamp exists, absent where none does:
FileDataalready recordsmodified_aton every write; the listing now surfaces it. A document persisted before the key existed listsNonerather than inventing a time.st_mtime, onlsandglob. A directory entry carriesNone.st_mtimethrough the wire.wire.FileEntry.modified_atdefaults toNone, so a client and a service on either side of this release keep understanding each other; a row from an older service validates toNone.ls -laoutput has no timestamp that survives locale, busybox and timezone, and a guessed time is worse than none.FileInfo's docstring says to read the key with.get()and treat a missing one as unknown.Additive only — the key is optional (
total=False, matching theFileDatasplit), so no existing constructor or consumer changes meaning.Verified: 1670 tests, 100% coverage, ruff/pyright/mypy clean.