Attachment Domain API
This namespace retains compatibility attachment records. New runtime applications use uploadAsset, immutable { assetId, version } references and authenticated bounded HTTP delivery. Legacy URL/upload helpers do not define the private runtime asset contract or grant model-input authority.
Usage boundary
Access the namespace on an explicitly configured root Cortex client. Host JWT and deployment-operator transports are distinct; validate current resource scope and do not infer authority from AuthContext metadata. See administrative operations.
Explicit attachment metadata and cursor pages
attach links already stored bytes to a selected memory space and owner. Required fields are storageId, memorySpaceId, userId, type, MIME type, filename and byte size; optional conversation/message/memory/artifact references, dimensions, duration in seconds and metadata describe the attachment. Metadata does not establish runtime private-asset ownership or authorize delivery. Invalid required fields/type/size are rejected.
get returns attachment metadata or null. list requires memorySpaceId and supports resource/owner/type filters, limit, cursor and sorting. It returns { attachments, total, cursor?, hasMore }; pass the returned cursor unchanged to the next page. Conversation/message/memory helper queries return arrays. delete and deleteMany report affected metadata/bytes according to protection checks; shared or retained versions may protect bytes.
import type { Cortex } from '@cortexmemory/sdk';
export async function readApprovedAttachmentPage(cortex: Cortex,
memorySpaceId: string, cursor?: string) {
const page = await cortex.attachments.list({ memorySpaceId, type: 'image', limit: 20, cursor });
return { files: page.attachments.map(file => ({ id: file.attachmentId,
filename: file.filename, bytes: file.size })), nextCursor: page.hasMore ? page.cursor : undefined };
}
Compatibility storage upload URL helpers are not the recommended private runtime asset flow. Ordinary runtime apps upload through CortexRuntimeClient.uploadAsset, obey the 20,000,000-byte limit and retrieve authorized bytes or owned object URLs through the private asset methods. See assets and media.
Parameter and result contracts
These are reference definitions for the explicit server APIs. Optional fields use ?; timestamps are milliseconds since epoch unless an operation accepts a Date. Resource identifiers and participant metadata do not grant runtime authority.
AttachParams
export interface AttachParams {
storageId: string;
memorySpaceId: string;
userId: string;
type: AttachmentType;
mimeType: string;
filename: string;
size: number;
conversationId?: string;
messageId?: string;
memoryId?: string;
artifactId?: string;
dimensions?: AttachmentDimensions;
duration?: number;
metadata?: Record<string, unknown>;
tenantId?: string;
}
| Field | Meaning and defaults |
|---|---|
storageId | Convex storage ID from upload |
memorySpaceId | Memory space to associate with |
userId | User who owns this attachment |
type | Type of attachment |
mimeType | MIME type (e.g., "image/png") |
filename | Original filename |
size | File size in bytes |
conversationId | Link to conversation (optional) |
messageId | Link to specific message (optional) |
memoryId | Link to memory (optional) |
artifactId | Link to artifact (optional) |
dimensions | Image/video dimensions (optional) |
duration | Audio/video duration in seconds (optional) |
metadata | Custom metadata (optional) |
tenantId | Multi-tenancy: tenant ID |
Attachment
export interface Attachment {
asset?: RuntimeAssetVersion;
_id: string;
attachmentId: string;
memorySpaceId: string;
tenantId?: string;
userId: string;
conversationId?: string;
messageId?: string;
memoryId?: string;
artifactId?: string;
storageId: string;
type: AttachmentType;
mimeType: string;
filename: string;
size: number;
extractedText?: string;
transcript?: string;
embedding?: number[];
dimensions?: AttachmentDimensions;
duration?: number;
metadata?: Record<string, unknown>;
createdAt: number;
updatedAt: number;
}
| Field | Meaning and defaults |
|---|---|
asset | Catalog metadata; storage IDs never confer private byte access. |
_id | Internal Convex document ID |
attachmentId | Unique attachment identifier |
memorySpaceId | Memory space isolation |
tenantId | Multi-tenancy: SaaS platform isolation |
userId | User who uploaded this attachment |
conversationId | Linked conversation (optional) |
messageId | Linked message (optional) |
memoryId | Linked memory (optional) |
artifactId | Linked artifact (optional) |
storageId | Convex storage ID for the file |
type | Type of attachment |
mimeType | MIME type (e.g., "image/png") |
filename | Original filename |
size | File size in bytes |
extractedText | Extracted text from OCR/PDF parsing (future) |
transcript | Audio/video transcript (future) |
embedding | Embedding for semantic search (future) |
dimensions | Image/video dimensions |
duration | Audio/video duration in seconds |
metadata | Custom metadata |
createdAt | Creation timestamp |
updatedAt | Last update timestamp |
AttachmentType
export type AttachmentType = "image" | "audio" | "video" | "file" | "pdf";
AttachmentDimensions
export interface AttachmentDimensions {
width: number;
height: number;
}
| Field | Meaning and defaults |
|---|---|
width | Width in pixels |
height | Height in pixels |
ListAttachmentsFilter
export interface ListAttachmentsFilter {
memorySpaceId: string;
conversationId?: string;
messageId?: string;
memoryId?: string;
artifactId?: string;
userId?: string;
type?: AttachmentType;
limit?: number;
cursor?: string;
sortBy?: "createdAt" | "updatedAt";
sortOrder?: "asc" | "desc";
tenantId?: string;
}
| Field | Meaning and defaults |
|---|---|
memorySpaceId | Required: memory space to list from |
conversationId | Filter by conversation |
messageId | Filter by message |
memoryId | Filter by memory |
artifactId | Filter by artifact |
userId | Filter by user |
type | Filter by attachment type |
limit | Maximum results (1-1000, default 50) |
cursor | Pagination cursor |
sortBy | Sort field |
sortOrder | Sort order |
tenantId | Multi-tenancy: tenant ID |
ListAttachmentsResult
export interface ListAttachmentsResult {
attachments: Attachment[];
total: number;
cursor?: string;
hasMore: boolean;
}
| Field | Meaning and defaults |
|---|---|
attachments | Array of attachments |
total | Total count matching filter |
cursor | Next page cursor (if more results exist) |
hasMore | Whether more results exist |
UploadUrlResult
export interface UploadUrlResult {
uploadUrl: string;
}
| Field | Meaning and defaults |
|---|---|
uploadUrl | Pre-signed upload URL |
DeleteManyAttachmentsResult
export interface DeleteManyAttachmentsResult {
binaryDispositions?: Array<{ attachmentId: string; disposition: BinaryDisposition }>;
deleted: number;
total: number;
errors?: Array<{
attachmentId: string;
error: string;
}>;
}
| Field | Meaning and defaults |
|---|---|
binaryDispositions | Byte outcomes, independent from the metadata deleted count. |
deleted | Number of attachments deleted |
total | Total number of attachments requested |
errors | Any errors encountered |
Public methods
The following signatures describe the TypeScript namespace. Parameter and result fields are defined on this page; the installed @cortexmemory/sdk declarations also provide their compile-time types. Signatures are reference notation, not application code to execute.
generateUploadUrl
Asset upload and delivery require a qualified authenticated backend capability.
cortex.attachments.generateUploadUrl(): Promise<UploadUrlResult>
attach
Register an uploaded file as an attachment.
cortex.attachments.attach(params: AttachParams): Promise<Attachment>
get
Get an attachment by ID.
cortex.attachments.get(attachmentId: string): Promise<Attachment | null>
getUrl
Asset upload and delivery require a qualified authenticated backend capability.
cortex.attachments.getUrl(attachmentId: string): Promise<string | null>
list
List attachments with comprehensive filters and pagination.
cortex.attachments.list(filter: ListAttachmentsFilter): Promise<ListAttachmentsResult>
getByConversation
Get attachments for a specific conversation.
cortex.attachments.getByConversation(conversationId: string, options?: { type?: "image" | "audio" | "video" | "file" | "pdf"; limit?: number }): Promise<Attachment[]>
getByMessage
Get attachments for a specific message.
cortex.attachments.getByMessage(messageId: string): Promise<Attachment[]>
count
Count attachments matching filters.
cortex.attachments.count(filter: { memorySpaceId: string; conversationId?: string; messageId?: string; userId?: string; type?: "image" | "audio" | "video" | "file" | "pdf"; tenantId?: string; }): Promise<number>
delete
Delete an attachment.
cortex.attachments.delete(attachmentId: string): Promise<boolean>
deleteMany
Bulk delete multiple attachments.
cortex.attachments.deleteMany(attachmentIds: string[]): Promise<DeleteManyAttachmentsResult>
upload
Upload a file and register it as an attachment in one operation.
cortex.attachments.upload(params: { file: Blob; memorySpaceId: string; userId: string; type: "image" | "audio" | "video" | "file" | "pdf"; filename: string; mimeType?: string; conversationId?: string; messageId?: string; memoryId?: string; artifactId?: string; dimensions?: { width: number; height: number }; duration?: number; metadata?: Record<string, unknown>; tenantId?: string; }): Promise<Attachment>
Errors and lifecycle
Validation, missing capability, authorization, stale version and partial/unknown committed outcomes are explicit. Inspect operation/write/deletion receipts before recovery; do not repeat an external effect under a new identity after uncertainty. Close owned clients and graph resources at the end of the server workflow.
See runtime client for ordinary app execution and error handling for recovery boundaries.