diff --git a/Makefile b/Makefile index 6c1ed017c0f9..364e61b53b32 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ docs: build: uv build +prerelease-dry-run: + uv run ./weave/scripts/prerelease_dry_run.py + prepare-release: docs build synchronize-base-object-schemas: diff --git a/dev_docs/RELEASE.md b/dev_docs/RELEASE.md index 6514f9d6730b..dcbba003e864 100644 --- a/dev_docs/RELEASE.md +++ b/dev_docs/RELEASE.md @@ -4,7 +4,9 @@ This document outlines how to publish a new Weave release to our public [PyPI pa 1. Verify the head of master is ready for release and announce merge freeze to the Weave team while the release is being published (Either ask an admin on the Weave repo to place a freeze on https://www.mergefreeze.com/ or use the mergefreeze Slack app if it is set up or just post in Slack) -2. You should also run through this [sample notebook](https://colab.research.google.com/drive/1DmkLzhFCFC0OoN-ggBDoG1nejGw2jQZy#scrollTo=29hJrcJQA7jZ) remember to install from master. You can also just run the [quickstart](http://wandb.me/weave_colab). +2. Manual Verifications: + - Run `make prerelease-dry-run` to verify that the dry run script works. + - You should also run through this [sample notebook](https://colab.research.google.com/drive/1DmkLzhFCFC0OoN-ggBDoG1nejGw2jQZy#scrollTo=29hJrcJQA7jZ) remember to install from master. You can also just run the [quickstart](http://wandb.me/weave_colab). 3. To prepare a PATCH release, go to GitHub Actions and run the [bump-python-sdk-version](https://github.com/wandb/weave/actions/workflows/bump_version.yaml) workflow on master. This will: diff --git a/docs/docs/guides/tracking/objects.md b/docs/docs/guides/tracking/objects.md index ffb26972f4cd..23e806d60b1f 100644 --- a/docs/docs/guides/tracking/objects.md +++ b/docs/docs/guides/tracking/objects.md @@ -58,6 +58,28 @@ Saving an object with a name will create the first version of that object if it +## Deleting an object + + + + To delete a version of an object, call `.delete()` on the object ref. + + ```python + weave.init('intro-example') + cat_names_ref = weave.ref('cat-names:v1') + cat_names_ref.delete() + ``` + + Trying to access a deleted object will result in an error. Resolving an object that has a reference to a deleted object will return a `DeletedRef` object in place of the deleted object. + + + + ```plaintext + This feature is not available in TypeScript yet. Stay tuned! + ``` + + + ## Ref styles A fully qualified weave object ref uri looks like this: diff --git a/docs/docs/guides/tracking/ops.md b/docs/docs/guides/tracking/ops.md index b5751ff57617..c78aacbb0efb 100644 --- a/docs/docs/guides/tracking/ops.md +++ b/docs/docs/guides/tracking/ops.md @@ -156,3 +156,25 @@ If you want to suppress the printing of call links during logging, you can set t ```bash export WEAVE_PRINT_CALL_LINK=false ``` + +## Deleting an op + + + + To delete a version of an op, call `.delete()` on the op ref. + + ```python + weave.init('intro-example') + my_op_ref = weave.ref('track_me:v1') + my_op_ref.delete() + ``` + + Trying to access a deleted op will result in an error. + + + + ```plaintext + This feature is not available in TypeScript yet. Stay tuned! + ``` + + diff --git a/docs/docs/guides/tracking/tracing.mdx b/docs/docs/guides/tracking/tracing.mdx index fbdf6bea96f9..e0efd4cd4453 100644 --- a/docs/docs/guides/tracking/tracing.mdx +++ b/docs/docs/guides/tracking/tracing.mdx @@ -5,6 +5,7 @@ import TracingCallsMacroImage from '@site/static/img/screenshots/calls_macro.png import TracingCallsFilterImage from '@site/static/img/screenshots/calls_filter.png'; import BasicCallImage from '@site/static/img/screenshots/basic_call.png'; + # Calls 0|[1-9]\\d*)\\. (?P0|[1-9]\\d*)\\. diff --git a/tests/trace/image_patch_test.py b/tests/trace/image_patch_test.py new file mode 100644 index 000000000000..6eca3482b5b9 --- /dev/null +++ b/tests/trace/image_patch_test.py @@ -0,0 +1,22 @@ +from tempfile import NamedTemporaryFile + +from weave.initialization import pil_image_thread_safety + + +def test_patching_import_order(): + # This test verifies the correct behavior if patching occurs after the construction + # of an image + assert pil_image_thread_safety._patched + pil_image_thread_safety.undo_threadsafe_patch_to_pil_image() + assert not pil_image_thread_safety._patched + import PIL + + image = PIL.Image.new("RGB", (10, 10)) + with NamedTemporaryFile(suffix=".png") as f: + image.save(f.name) + image = PIL.Image.open(f.name) + + pil_image_thread_safety.apply_threadsafe_patch_to_pil_image() + assert pil_image_thread_safety._patched + + image.crop((0, 0, 10, 10)) diff --git a/tests/trace/test_dictifiable.py b/tests/trace/test_dictifiable.py new file mode 100644 index 000000000000..e99ecf29e130 --- /dev/null +++ b/tests/trace/test_dictifiable.py @@ -0,0 +1,45 @@ +import weave + + +def test_dictifiable(client): + class NonDictifiable: + attr: int + + def __init__(self, attr: int): + self.attr = attr + + class Dictifiable: + attr: int + + def __init__(self, attr: int): + self.attr = attr + + def to_dict(self): + return {"attr": self.attr} + + @weave.op + def func(d: Dictifiable, nd: NonDictifiable) -> dict: + return { + "d": Dictifiable(d.attr), + "nd": NonDictifiable(nd.attr), + } + + val = 42 + d = Dictifiable(val) + nd = NonDictifiable(val) + res = func(d, nd) + assert isinstance(res["d"], Dictifiable) + assert res["d"].attr == val + assert isinstance(res["nd"], NonDictifiable) + assert res["nd"].attr == val + + call = func.calls()[0] + + assert call.inputs["d"] == {"attr": val} + assert call.inputs["nd"].startswith( + ".NonDictifiable object at" + ) + assert call.output["d"] == {"attr": val} + assert call.output["nd"].startswith( + ".NonDictifiable object at" + ) diff --git a/tests/trace/type_handlers/Image/image_test.py b/tests/trace/type_handlers/Image/image_test.py index 316bbef917ab..a5dcbc37dc3a 100644 --- a/tests/trace/type_handlers/Image/image_test.py +++ b/tests/trace/type_handlers/Image/image_test.py @@ -149,20 +149,19 @@ def accept_image_jpg_pillow(val): file_path.unlink() +def make_random_image(image_size: tuple[int, int] = (1024, 1024)): + random_colour = ( + random.randint(0, 255), + random.randint(0, 255), + random.randint(0, 255), + ) + return Image.new("RGB", image_size, random_colour) + + @pytest.fixture def dataset_ref(client): # This fixture represents a saved dataset containing images - IMAGE_SIZE = (1024, 1024) N_ROWS = 50 - - def make_random_image(): - random_colour = ( - random.randint(0, 255), - random.randint(0, 255), - random.randint(0, 255), - ) - return Image.new("RGB", IMAGE_SIZE, random_colour) - rows = [{"img": make_random_image()} for _ in range(N_ROWS)] dataset = weave.Dataset(rows=rows) ref = weave.publish(dataset) @@ -202,3 +201,18 @@ async def test_many_images_will_consistently_log(): # But if there's an issue, the stderr will contain `Task failed:` assert "Task failed" not in res.stderr + + +def test_images_in_load_of_dataset(client): + N_ROWS = 50 + rows = [{"img": make_random_image()} for _ in range(N_ROWS)] + dataset = weave.Dataset(rows=rows) + ref = weave.publish(dataset) + + dataset = ref.get() + for gotten_row, local_row in zip(dataset, rows): + assert isinstance(gotten_row["img"], Image.Image) + assert gotten_row["img"].size == local_row["img"].size + assert gotten_row["img"].tobytes() == local_row["img"].tobytes() + + return ref diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/DatasetVersionPage.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/DatasetVersionPage.tsx index 488f5170fe14..68112d9b904a 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/DatasetVersionPage.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/DatasetVersionPage.tsx @@ -5,6 +5,7 @@ import React, {useMemo} from 'react'; import {Icon} from '../../../../Icon'; import {LoadingDots} from '../../../../LoadingDots'; import {Tailwind} from '../../../../Tailwind'; +import {Timestamp} from '../../../../Timestamp'; import {WeaveCHTableSourceRefContext} from '../pages/CallPage/DataTableView'; import {ObjectViewerSection} from '../pages/CallPage/ObjectViewerSection'; import {objectVersionText} from '../pages/common/Links'; @@ -30,6 +31,7 @@ export const DatasetVersionPage: React.FC<{ const projectName = objectVersion.project; const objectName = objectVersion.objectId; const objectVersionIndex = objectVersion.versionIndex; + const {createdAtMs} = objectVersion; const objectVersions = useRootObjectVersions( entityName, @@ -76,7 +78,7 @@ export const DatasetVersionPage: React.FC<{ } headerContent={ -
+

Name

Version

{objectVersionIndex}

+
+

Created

+

+ +

+
{objectVersion.userId && (

Created by

diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/grid/pagination.ts b/weave-js/src/components/PagePanelComponents/Home/Browse3/grid/pagination.ts index ed9adf9d22a2..45eea688a37e 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/grid/pagination.ts +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/grid/pagination.ts @@ -1,7 +1,7 @@ import {GridPaginationModel} from '@mui/x-data-grid-pro'; const MAX_PAGE_SIZE = 100; -export const DEFAULT_PAGE_SIZE = 100; +export const DEFAULT_PAGE_SIZE = 50; export const getValidPaginationModel = ( queryPage: string | undefined, diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/CallDetails.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/CallDetails.tsx index 03519960bf37..3e2cb8886771 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/CallDetails.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/CallDetails.tsx @@ -189,6 +189,7 @@ export const CallDetails: FC<{ entity={call.entity} project={call.project} allowedColumnPatterns={ALLOWED_COLUMN_PATTERNS} + paginationModel={isPeeking ? {page: 0, pageSize: 10} : undefined} /> ); if (isPeeking) { diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/ValueViewString.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/ValueViewString.tsx index 0e017b929feb..2de53bffead0 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/ValueViewString.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/ValueViewString.tsx @@ -39,13 +39,13 @@ const Spacer = styled.div` `; Spacer.displayName = 'S.Spacer'; -const Collapsed = styled.div<{hasScrolling: boolean}>` +const Collapsed = styled.div` min-height: 38px; line-height: 38px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - cursor: ${props => (props.hasScrolling ? 'pointer' : 'default')}; + cursor: pointer; `; Collapsed.displayName = 'S.Collapsed'; @@ -100,12 +100,10 @@ export const ValueViewString = ({value, isExpanded}: ValueViewStringProps) => { setMode(hasScrolling ? (isExpanded ? 1 : 0) : 0); }, [hasScrolling, isExpanded]); - const onClick = hasScrolling - ? () => { - const numModes = hasFull ? 3 : 2; - setMode((mode + 1) % numModes); - } - : undefined; + const onClick = () => { + const numModes = hasFull ? 3 : 2; + setMode((mode + 1) % numModes); + }; const copy = useCallback(() => { copyToClipboard(value); toast('Copied to clipboard'); @@ -209,9 +207,5 @@ export const ValueViewString = ({value, isExpanded}: ValueViewStringProps) => { ); } - return ( - - {content} - - ); + return {content}; }; diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTable.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTable.tsx index 3632664aaf09..fd8ac8c888e6 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTable.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTable.tsx @@ -941,7 +941,6 @@ export const CallsTable: FC<{ paginationMode="server" paginationModel={paginationModel} onPaginationModelChange={onPaginationModelChange} - pageSizeOptions={[DEFAULT_PAGE_SIZE]} // PAGINATION SECTION END rowHeight={38} columns={muiColumns} @@ -949,6 +948,7 @@ export const CallsTable: FC<{ rowSelectionModel={rowSelectionModel} // columnGroupingModel={groupingModel} columnGroupingModel={columns.colGroupingModel} + hideFooter={!callsLoading && callsTotal === 0} hideFooterSelectedRowCount onColumnWidthChange={newCol => { setUserDefinedColumnWidths(curr => { @@ -1022,7 +1022,7 @@ export const CallsTable: FC<{ ); }, columnMenu: CallsCustomColumnMenu, - pagination: PaginationButtons, + pagination: () => , columnMenuSortDescendingIcon: IconSortDescending, columnMenuSortAscendingIcon: IconSortAscending, columnMenuHideIcon: IconNotVisible, diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTableButtons.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTableButtons.tsx index a69b358fc633..52e31390c85c 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTableButtons.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallsPage/CallsTableButtons.tsx @@ -26,6 +26,7 @@ import classNames from 'classnames'; import React, {Dispatch, FC, SetStateAction, useRef, useState} from 'react'; import * as userEvents from '../../../../../../integrations/analytics/userEvents'; +import {Select} from '../../../../../Form/Select'; import {useWFHooks} from '../wfReactInterface/context'; import {Query} from '../wfReactInterface/traceServerClientInterface/query'; import { @@ -642,7 +643,16 @@ curl '${baseUrl}/calls/stream_query' \\ return baseCurl; } -export const PaginationButtons = () => { +type PageSizeOption = { + readonly value: number; + readonly label: string; +}; + +type PaginationButtonsProps = { + hideControls?: boolean; +}; + +export const PaginationButtons = ({hideControls}: PaginationButtonsProps) => { const apiRef = useGridApiContext(); const page = useGridSelector(apiRef, gridPageSelector); const pageCount = useGridSelector(apiRef, gridPageCountSelector); @@ -661,35 +671,81 @@ export const PaginationButtons = () => { const start = rowCount > 0 ? page * pageSize + 1 : 0; const end = Math.min(rowCount, (page + 1) * pageSize); + const pageSizes = [10, 25, 50, 100]; + if (!pageSizes.includes(pageSize)) { + pageSizes.push(pageSize); + pageSizes.sort((a, b) => a - b); + } + const pageSizeOptions = pageSizes.map(sz => ({ + value: sz, + label: sz.toString(), + })); + const pageSizeValue = pageSizeOptions.find(o => o.value === pageSize); + const onPageSizeChange = (option: PageSizeOption | null) => { + if (option) { + apiRef.current.setPageSize(option.value); + } + }; + return ( - - +
+ + + Response selected + +
) : ( )}
@@ -95,12 +128,11 @@ export const ChoicesDrawer = ({ choice={c} isStructuredOutput={isStructuredOutput} choiceIndex={index} - isNested />
))}
- + ); }; diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/ChoicesViewCarousel.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/ChoicesViewCarousel.tsx index 3addbdded819..0612d7d8096f 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/ChoicesViewCarousel.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/ChoicesViewCarousel.tsx @@ -69,7 +69,7 @@ export const ChoicesViewCarousel = ({ icon="visible" onClick={() => setIsDrawerOpen(true)} tooltip="View all choices"> - Review + View trials } diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/MessagePanel.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/MessagePanel.tsx index 8cec95707fa7..560585fd10da 100644 --- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/MessagePanel.tsx +++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ChatView/MessagePanel.tsx @@ -122,8 +122,10 @@ export const MessagePanel = ({
{messageHeader} {isPlayground && editorHeight ? ( @@ -167,7 +169,7 @@ export const MessagePanel = ({ )}
- {isOverflowing && !editorHeight && ( + {isOverflowing && !hasToolCalls && !editorHeight && ( { return (
+ className={classNames('flex w-full items-center justify-center', { + 'pt-[4px]': isShowingMore, + [`absolute z-[1] mt-[-32px] rounded-b-xl bg-gradient-to-t from-70% pb-[4px] pt-[16px] ${ + isUser ? 'from-[#f4fbe8]' : 'from-white' + } to-transparent`]: !isShowingMore, + })}>