// file_storage.go declares the narrow FileStorage interface that the // four v4 file tools (file_save, file_get, file_list, file_delete) // need at execute time. // // Why a narrow interface (vs importing pkg/logic/skills directly): same // cycle constraint as kv_storage.go — pkg/logic/skills imports // pkg/skilltools, so we mirror the FileMeta shape here and let // pkg/logic/mort.go adapt at wiring time. // // FileDomainMeta is field-for-field with skills.FileMeta; the production // adapter is a struct copy. package tools import ( "context" "errors" "time" ) // FileStorage is the narrow surface file tools need from the skills // package. Production wiring (mort.go) bridges *skills.System.Storage(). // nil-safe: tools constructed against a nil FileStorage surface "not // configured" at the first call. type FileStorage interface { FileSave(ctx context.Context, meta FileDomainMeta, content []byte) (string, error) FileGet(ctx context.Context, fileID string) (*FileDomainMeta, []byte, error) FileList(ctx context.Context, skillID, scope string) ([]FileDomainMeta, error) FileDelete(ctx context.Context, fileID string) error FileUsageBytes(ctx context.Context, skillID string) (int64, error) } // FileDomainMeta mirrors skills.FileMeta. Field-for-field; the // production adapter is a struct copy. type FileDomainMeta struct { ID string // UUID, the public file_id SkillID string Scope string Name string ContentHash string // SHA256 hex MimeType string SizeBytes int64 CreatedAt time.Time } // ErrFileNotFound mirrors skills.ErrFileNotFound. The production // adapter returns this sentinel when wrapping a skills.ErrFileNotFound; // tools detect it with errors.Is to surface a "not_found" string to the // LLM rather than a generic error. var ErrFileNotFound = errors.New("file: not found")