Deleted the model compatibility migration file as it is no longer needed. Updated podcast artifact initialization to replace storage-related imports with the new record module, streamlining the codebase. Cleaned up unnecessary imports in the podcast API routes and rendering tasks.
Passing OpenRouter's metadata filters does not prove a model can complete a
turn through this harness, so dead-but-advertised models kept reaching users
and failing mid-stream. A new model_compatibility table holds one verdict per
model, a weekly Celery sweep re-probes stale entries, and catalogue
generation reads the blocked ids back so those models are never offered.
Also excludes :batch variants, which advertise full chat metadata and then
reject completions outright.
Auto-pin now falls through to Auto when an explicitly selected global config
is absent from the current worker's catalogue. Returning it handed
load_llm_bundle an id it could not resolve, ending the turn with SERVER_ERROR
on one of the four uvicorn workers while the identical request succeeded on
the others. Catalogue refresh also re-materializes GLOBAL_MODELS, which
previously kept its boot snapshot until restart.
On the web side a single dropped connection surfaced as one toast per
in-flight query and dozens of PostHog exceptions, with no retry button.
Network errors now share a toast id, are deduped per endpoint before capture,
carry host and online context, and count as retryable.
Consolidates the model filter helpers duplicated between the model list and
OpenRouter services into openrouter_model_normalizer, renames OoxmlDefect to
OoxmlError, and includes a ruff format and import-order pass.
Co-authored-by: Cursor <cursoragent@cursor.com>
The media-alignment record path reads workspace_id and (nullable) artifact_id
off the VideoPresentation row; the SimpleNamespace fake omitted them. Add both
so the billing tests exercise the real record path.
Threads minted by the authenticated artifact door are empty vessels for the
subagent's sandbox key and never streamed to. Tag them with a dedicated
ARTIFACT_API_SOURCE and exclude that source from the thread list and search
queries so they stay out of the sidebar.
Each door call mints a throwaway thread that grabs a per-workspace sandbox
session; nothing released it, so a couple of calls hit the cap and blocked
every other conversation (chat included) until the idle reaper ran.
run_deliverable_subagent now terminates the thread's session in a finally,
freeing the slot immediately.
The door skipped two things a chat turn does. It parsed only the document
tool's receipt shape, so image artifacts (artifact_id, no files) came back
as an empty list; now every artifact_id in the run's tool messages is
collected and its files hydrated from the DB. It also never committed the
turn's working copy, so save_artifact's staged body was never recorded or
indexed and the document sat pending; run_deliverable_subagent now runs the
same end-of-turn commit chat uses, which enqueues indexing.
- Updated `ArtifactCard` to ensure proper overflow handling and prevent layout issues with long text.
- Adjusted styles in `ArtifactsLibrary` for better responsiveness and to manage overflow in the grid layout.
- Added `selectedCardToolCallId` to the artifact panel state for improved tracking of selected artifacts.
- Updated `openArtifactPanelAtom` to accept `selectedCardToolCallId` when opening the panel.
- Modified `ArtifactCard` component to pass `toolCallId` when opening the artifact panel, ensuring correct selection highlighting.
- Refactored `scroll-to-artifact` logic to utilize the new `selectedCardToolCallId` for better artifact navigation.
- Adjusted styles in the artifact card to visually indicate the selected state.
- Introduced `useArtifactDeepLink` hook to manage deep linking for artifacts in chat.
- Updated `useSyncChatArtifacts` to return loading states and artifacts for better UI feedback.
- Added `ThreadMessagesSkeletonBody` component for improved loading experience in the thread view.
- Refactored `ArtifactCard` to support deep linking and streamlined artifact display logic.
- Removed unused media viewer dialog component to simplify the artifacts library UI.
Add app/artifacts/access with a single authenticated door
(POST /workspaces/{id}/artifacts/generate) that mints a blank thread, resolves
the workspace chat model, runs the chat-turn credit seam, and invokes the
shared run_deliverable_subagent. REST now produces artifacts through the exact
engine chat uses, images included. An anonymous door is deferred.
The extracted generation engine (core registry/context/result, image
generator/executor/resolve/schemas) plus its agent/REST/public doors just
re-sliced the deliverables subagent's own image tool and introduced drift
between chat and REST paths. Restore generate_image.py to its self-contained
form and delete the engine, its doors, the anonymous quota/config scaffolding,
and the tests that only covered the removed code.
Test URL normalization, base64 decoding, and anonymous model resolution for
the image generator, plus the public door's per-IP cap and Turnstile paths.
Each door iterates the same registry and runs the generic pipeline with its
own context: the agent tool returns a receipt Command, the authenticated REST
route returns a typed artifact response, and the public SEO funnel returns raw
bytes behind no-login mode with a per-IP cap and Turnstile. Reduce the
generate_image tool to a thin binding of the image generator's agent door.
Add a generation core where one generic pipeline (resolve, meter, deliver)
runs against a request-scoped context: authenticated callers bill a workspace
wallet and persist an Artifact, anonymous callers skip both and get raw bytes.
Register the image kind as the first generator and share image-byte decoding
between the persistence path and the no-persist door.
- Introduced a new `DocumentTypeFilterList` component for improved filtering of document types.
- Added search functionality to filter document types based on user input.
- Implemented scroll position tracking to enhance user experience in the filter list.
- Updated `DocumentsFilters` to integrate the new filtering component and handle mobile responsiveness.
- Refactored existing state management for clarity and efficiency.
- Introduced support for displaying an `ArtifactFormatIcon` when the document type is "ARTIFACT".
- Updated the `FORMAT_META` to include a new presentation-only key for artifacts, enhancing the visual representation in the UI.
- Ensured consistent handling of document types across the application.
- Added `document_id` to artifact listing for improved metadata association.
- Introduced `ArtifactFormatIcon` and `ArtifactFormatLabel` components for better visual representation of artifact formats.
- Updated various components to utilize new format handling, ensuring consistent display across the application.
- Refactored artifact-related schemas and hooks to accommodate new format data.
- Enhanced unit tests to cover new functionality and ensure robustness.
- Updated `ArtifactViewerContent` to conditionally display download filename based on workspace validity.
- Added `refetchOnWindowFocus` option to artifact query for improved data freshness.
- Replaced `documentStatus` with a Zod enum for `indexing_status` in artifact schemas.
- Refactored `collectArtifacts` to return `ArtifactCandidate` and adjusted related functions for better artifact management.
- Removed unused imports and streamlined the `ArtifactRow` component for clarity.
Convert READY rows missing artifact_id: push the stored audio into a
new Artifact, stamp artifact_id, and repoint chat messages and public
snapshots. Idempotent and guarded to no-op once podcasts is renamed.
Rename podcasts -> podcast_runs and treat the run row as job state
only: delivered audio and its markdown live in the Artifact, so the
row drops storage_backend/storage_key/file_location and gains
artifact_id. mark_ready commits status and artifact_id atomically,
preserving the READY <-> artifact_id invariant that Zero publishes.
Public shares stream audio through the artifact content route and get
artifact_id + workspace_id injected at snapshot time; the authenticated
player and library read artifactId from Zero. Retire the legacy
authenticated stream route, the podcast storage helpers, and the REST
list endpoint.
Passing OpenRouter's metadata filters does not prove a model can complete a
turn through this harness, so dead-but-advertised models kept reaching users
and failing mid-stream. A new model_compatibility table holds one verdict per
model, a weekly Celery sweep re-probes stale entries, and catalogue
generation reads the blocked ids back so those models are never offered.
Also excludes :batch variants, which advertise full chat metadata and then
reject completions outright.
Auto-pin now falls through to Auto when an explicitly selected global config
is absent from the current worker's catalogue. Returning it handed
load_llm_bundle an id it could not resolve, ending the turn with SERVER_ERROR
on one of the four uvicorn workers while the identical request succeeded on
the others. Catalogue refresh also re-materializes GLOBAL_MODELS, which
previously kept its boot snapshot until restart.
On the web side a single dropped connection surfaced as one toast per
in-flight query and dozens of PostHog exceptions, with no retry button.
Network errors now share a toast id, are deduped per endpoint before capture,
carry host and online context, and count as retryable.
Consolidates the model filter helpers duplicated between the model list and
OpenRouter services into openrouter_model_normalizer, renames OoxmlDefect to
OoxmlError, and includes a ruff format and import-order pass.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Updated `list_artifacts` to accept an optional `thread_id` parameter for filtering artifacts by thread.
- Modified the query to conditionally include the `thread_id` in the selection criteria.
- Enhanced frontend components to support thread-specific artifact fetching and display.
- Added unit tests to verify the new functionality for scoping artifacts to a specific thread.
Images live in Artifacts now; the generate_image tool writes an Artifact
directly and no longer inserts here. This is image's contract step, mirroring
video's 180.
- guarded like 180: aborts while any convertible row (one still holding
response_data) has no Artifact, so backfill_image_artifacts.py can't be
skipped and images can't be lost. Error-only rows carry no image and don't
block the drop
- drops only image_generations + its indexes and strips the
image_generations RBAC permissions; the image config table and
imagegenprovider enum stay, the tool still uses them
- downgrade recreates the table and restores the grants migration 93 gave
the system roles
Video now delivers into an Artifact like image and podcast. The run row
becomes a lifecycle record and the Remotion payload lives in the Artifact.
- run carries artifact_id; the tool returns artifact_id + workspace_id and
the frontend renders from the Artifact
- public shares serve video and slide audio through artifact-scoped routes
behind the snapshot allowlist, replacing the broken audio_file path
- purge_document_blobs collects slide audio storage keys so deleting a video
Artifact no longer orphans them
- backfill_video_artifacts.py converts legacy rows and repoints chat and
snapshot payloads (run before the slim migration)
- migrations: 179 adds artifact_id (expand); 180 renames the table to
video_presentation_runs, drops slides/scene_codes, adds error, and
publishes to Zero (contract). 180 aborts if any delivered run still lacks
an Artifact, so the backfill can't be skipped
- publish video_presentation_runs to Zero so in-flight and failed runs reach
the library by push; retire the legacy REST routes, schema, and poller
- Added a new `SpreadsheetGrid` component to render Excel sheets using `react-data-grid`.
- Enhanced the viewer to display worksheets with dynamic column and row generation.
- Updated loading and error handling messages for better user experience.
- Refactored existing table structure to utilize the new grid component for better performance and styling.
ADR 0003 places an artifact body at `documents/Artifacts/<title>.md`, but
the allocator was writing to the root of the tree. The row takes the
matching folder_id at creation: git projection derives it from the path,
yet only once the revision is indexed and never at all for a
Postgres-only workspace.
A reasoning model replies with a list of blocks rather than a string, so
stringifying it wrote the model's entire thinking into the revision's
commit message. Reuse the existing extractor, which keeps text and drops
reasoning.
- Added state management for pending folder deletion and deletion status.
- Refactored folder deletion logic to include a confirmation dialog before proceeding with the deletion.
- Integrated alert dialog to notify users of the deletion action and its consequences.
Run before the migration that drops the table: production holds rows whose
bytes live in the provider payload or the object store, and whose tool payloads
are still stored in chat messages and public snapshots. Converts each row to an
Artifact and repoints those payloads. Re-runnable — converted rows are skipped.
generate_image now bills, calls the provider once and persists through
save_artifact, with the generation parameters and revised prompt kept as
provenance. The ImageGeneration model, its routes, schemas, RBAC permissions
and per-image access tokens are gone, along with the frontend service and
types; viewers fetch the primary file through the artifact manifest.
Shared chats keep working: the snapshot stores the artifact ids its messages
reference and a public route serves only those, so a token grants the thread's
own artifacts rather than the workspace's.