Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(weave): Refactor and rename code to more appropriately handle builtin_object_class not base_object_class #3229

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# BaseObjectClasses
# BuiltinObjectClasses

## Refresher on Objects and object storage

Expand Down Expand Up @@ -79,11 +79,11 @@ While many Weave Objects are free-form and user-defined, there is often a need f

Here's how to define and use a validated base object:

1. **Define your schema** (in `weave/trace_server/interface/base_object_classes/your_schema.py`):
1. **Define your schema** (in `weave/trace_server/interface/builtin_object_classes/your_schema.py`):

```python
from pydantic import BaseModel
from weave.trace_server.interface.base_object_classes import base_object_def
from weave.trace_server.interface.builtin_object_classes import base_object_def

class NestedConfig(BaseModel):
setting_a: int
Expand Down Expand Up @@ -116,7 +116,7 @@ curl -X POST 'https://trace.wandb.ai/obj/create' \
"project_id": "user/project",
"object_id": "my_config",
"val": {...},
"set_base_object_class": "MyConfig"
"object_class": "MyConfig"
}
}'

Expand Down Expand Up @@ -154,38 +154,38 @@ Run `make synchronize-base-object-schemas` to ensure the frontend TypeScript typ

### Architecture Flow

1. Define your schema in a python file in the `weave/trace_server/interface/base_object_classes/test_only_example.py` directory. See `weave/trace_server/interface/base_object_classes/test_only_example.py` as an example.
2. Make sure to register your schemas in `weave/trace_server/interface/base_object_classes/base_object_registry.py` by calling `register_base_object`.
1. Define your schema in a python file in the `weave/trace_server/interface/builtin_object_classes/test_only_example.py` directory. See `weave/trace_server/interface/builtin_object_classes/test_only_example.py` as an example.
2. Make sure to register your schemas in `weave/trace_server/interface/builtin_object_classes/builtin_object_registry.py` by calling `register_base_object`.
3. Run `make synchronize-base-object-schemas` to generate the frontend types.
* The first step (`make generate_base_object_schemas`) will run `weave/scripts/generate_base_object_schemas.py` to generate a JSON schema in `weave/trace_server/interface/base_object_classes/generated/generated_base_object_class_schemas.json`.
* The second step (yarn `generate-schemas`) will read this file and use it to generate the frontend types located in `weave-js/src/components/PagePanelComponents/Home/Browse3/pages/wfReactInterface/generatedBaseObjectClasses.zod.ts`.
* The first step (`make generate_base_object_schemas`) will run `weave/scripts/generate_base_object_schemas.py` to generate a JSON schema in `weave/trace_server/interface/builtin_object_classes/generated/generated_builtin_object_class_schemas.json`.
* The second step (yarn `generate-schemas`) will read this file and use it to generate the frontend types located in `weave-js/src/components/PagePanelComponents/Home/Browse3/pages/wfReactInterface/generatedBuiltinObjectClasses.zod.ts`.
4. Now, each use case uses different parts:
1. `Python Writing`. Users can directly import these classes and use them as normal Pydantic models, which get published with `weave.publish`. The python client correct builds the requisite payload.
2. `Python Reading`. Users can `weave.ref().get()` and the weave python SDK will return the instance with the correct type. Note: we do some special handling such that the returned object is not a WeaveObject, but literally the exact pydantic class.
3. `HTTP Writing`. In cases where the client/user does not want to add the special type information, users can publish base objects by setting the `set_base_object_class` setting on `POST obj/create` to the name of the class. The weave server will validate the object against the schema, update the metadata fields, and store the object.
3. `HTTP Writing`. In cases where the client/user does not want to add the special type information, users can publish builtin objects by setting the `object_class` setting on `POST obj/create` to the name of the class. The weave server will validate the object against the schema, update the metadata fields, and store the object.
tssweeney marked this conversation as resolved.
Show resolved Hide resolved
4. `HTTP Reading`. When querying for objects, the server will return the object with the correct type if the `base_object_class` metadata field is set.
5. `Frontend`. The frontend will read the zod schema from `weave-js/src/components/PagePanelComponents/Home/Browse3/pages/wfReactInterface/generatedBaseObjectClasses.zod.ts` and use that to provide compile time type safety when using `useBaseObjectInstances` and runtime type safety when using `useCreateBaseObjectInstance`.
5. `Frontend`. The frontend will read the zod schema from `weave-js/src/components/PagePanelComponents/Home/Browse3/pages/wfReactInterface/generatedBuiltinObjectClasses.zod.ts` and use that to provide compile time type safety when using `useBaseObjectInstances` and runtime type safety when using `useCreateBaseObjectInstance`.
* Note: it is critical that all techniques produce the same digest for the same data - which is tested in the tests. This way versions are not thrashed by different clients/users.

```mermaid
graph TD
subgraph Schema Definition
F["weave/trace_server/interface/<br>base_object_classes/your_schema.py"] --> |defines| P[Pydantic BaseObject]
P --> |register_base_object| R["base_object_registry.py"]
P --> |register_base_object| R["builtin_object_registry.py"]
end

subgraph Schema Generation
M["make synchronize-base-object-schemas"] --> G["make generate_base_object_schemas"]
G --> |runs| S["weave/scripts/<br>generate_base_object_schemas.py"]
R --> |import registered classes| S
S --> |generates| J["generated_base_object_class_schemas.json"]
M --> |yarn generate-schemas| Z["generatedBaseObjectClasses.zod.ts"]
S --> |generates| J["generated_builtin_object_class_schemas.json"]
M --> |yarn generate-schemas| Z["generatedBuiltinObjectClasses.zod.ts"]
J --> Z
end

subgraph "Trace Server"
subgraph "HTTP API"
R --> |validates using| HW["POST obj/create<br>set_base_object_class"]
R --> |validates using| HW["POST obj/create<br>object_class"]
HW --> DB[(Weave Object Store)]
HR["POST objs/query<br>base_object_classes"] --> |Filters base_object_class| DB
end
Expand All @@ -203,7 +203,7 @@ graph TD
Z --> |import| UBI["useBaseObjectInstances"]
Z --> |import| UCI["useCreateBaseObjectInstance"]
UBI --> |Filters base_object_class| HR
UCI --> |set_base_object_class| HW
UCI --> |object_class| HW
UI[React UI] --> UBI
UI --> UCI
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)
from tests.trace.util import client_is_sqlite
from weave.trace.weave_client import WeaveClient
from weave.trace_server.interface.base_object_classes.actions import (
from weave.trace_server.interface.builtin_object_classes.actions import (
ActionSpec,
)
from weave.trace_server.trace_server_interface import (
Expand Down
2 changes: 1 addition & 1 deletion tests/trace/test_actions_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import weave
from tests.trace.util import client_is_sqlite
from weave.trace.weave_client import WeaveClient
from weave.trace_server.interface.base_object_classes.actions import (
from weave.trace_server.interface.builtin_object_classes.actions import (
ActionSpec,
)
from weave.trace_server.trace_server_interface import (
Expand Down
16 changes: 8 additions & 8 deletions tests/trace/test_base_object_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from weave.trace.refs import ObjectRef
from weave.trace.weave_client import WeaveClient
from weave.trace_server import trace_server_interface as tsi
from weave.trace_server.interface.base_object_classes.test_only_example import (
from weave.trace_server.interface.builtin_object_classes.test_only_example import (
TestOnlyNestedBaseModel,
)

Expand Down Expand Up @@ -139,7 +139,7 @@ def test_interface_creation(client):
"project_id": client._project_id(),
"object_id": nested_obj_id,
"val": nested_obj.model_dump(),
"set_base_object_class": "TestOnlyNestedBaseObject",
"builtin_object_class": "TestOnlyNestedBaseObject",
}
}
)
Expand All @@ -164,7 +164,7 @@ def test_interface_creation(client):
"project_id": client._project_id(),
"object_id": top_level_obj_id,
"val": top_obj.model_dump(),
"set_base_object_class": "TestOnlyExample",
"builtin_object_class": "TestOnlyExample",
}
}
)
Expand Down Expand Up @@ -271,7 +271,7 @@ def test_digest_equality(client):
"project_id": client._project_id(),
"object_id": nested_obj_id,
"val": nested_obj.model_dump(),
"set_base_object_class": "TestOnlyNestedBaseObject",
"builtin_object_class": "TestOnlyNestedBaseObject",
}
}
)
Expand Down Expand Up @@ -300,7 +300,7 @@ def test_digest_equality(client):
"project_id": client._project_id(),
"object_id": top_level_obj_id,
"val": top_obj.model_dump(),
"set_base_object_class": "TestOnlyExample",
"builtin_object_class": "TestOnlyExample",
}
}
)
Expand All @@ -322,7 +322,7 @@ def test_schema_validation(client):
"object_id": "nested_obj",
# Incorrect schema, should raise!
"val": {"a": 2},
"set_base_object_class": "TestOnlyNestedBaseObject",
"builtin_object_class": "TestOnlyNestedBaseObject",
}
}
)
Expand All @@ -340,7 +340,7 @@ def test_schema_validation(client):
"_class_name": "TestOnlyNestedBaseObject",
"_bases": ["BaseObject", "BaseModel"],
},
"set_base_object_class": "TestOnlyNestedBaseObject",
"builtin_object_class": "TestOnlyNestedBaseObject",
}
}
)
Expand All @@ -359,7 +359,7 @@ def test_schema_validation(client):
"_class_name": "TestOnlyNestedBaseObject",
"_bases": ["BaseObject", "BaseModel"],
},
"set_base_object_class": "TestOnlyExample",
"builtin_object_class": "TestOnlyExample",
}
}
)
Expand Down
12 changes: 6 additions & 6 deletions weave-js/scripts/generate-schemas.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# Exit on error
set -e

SCHEMA_INPUT_PATH="../weave/trace_server/interface/base_object_classes/generated/generated_base_object_class_schemas.json"
SCHEMA_OUTPUT_PATH="./src/components/PagePanelComponents/Home/Browse3/pages/wfReactInterface/generatedBaseObjectClasses.zod.ts"
SCHEMA_INPUT_PATH="../weave/trace_server/interface/builtin_object_classes/generated/generated_builtin_object_class_schemas.json"
SCHEMA_OUTPUT_PATH="./src/components/PagePanelComponents/Home/Browse3/pages/wfReactInterface/generatedBuiltinObjectClasses.zod.ts"

echo "Generating schemas..."

Expand All @@ -13,10 +13,10 @@ yarn quicktype -s schema "$SCHEMA_INPUT_PATH" -o "$SCHEMA_OUTPUT_PATH" --lang ty

# Transform the schema to extract the type map
sed -i.bak '
# Find the GeneratedBaseObjectClassesZodSchema definition and capture its contents
/export const GeneratedBaseObjectClassesZodSchema = z.object({/,/});/ {
# Find the GeneratedBuiltinObjectClassesZodSchema definition and capture its contents
/export const GeneratedBuiltinObjectClassesZodSchema = z.object({/,/});/ {
# Replace the opening line with typeMap declaration
s/export const GeneratedBaseObjectClassesZodSchema = z.object({/export const baseObjectClassRegistry = ({/
s/export const GeneratedBuiltinObjectClassesZodSchema = z.object({/export const builtinObjectClassRegistry = ({/
# Store the pattern
h
# If this is the last line (with closing brace), append the schema definition
Expand All @@ -27,7 +27,7 @@ sed -i.bak '
s/.*//
i\
\
export const GeneratedBaseObjectClassesZodSchema = z.object(baseObjectClassRegistry)
export const GeneratedBuiltinObjectClassesZodSchema = z.object(builtinObjectClassRegistry)
}
}
' "$SCHEMA_OUTPUT_PATH"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {AnnotationSpec} from '../../pages/wfReactInterface/generatedBaseObjectClasses.zod';
import {AnnotationSpec} from '../../pages/wfReactInterface/generatedBuiltinObjectClasses.zod';
import {Feedback} from '../../pages/wfReactInterface/traceServerClientTypes';

export const HUMAN_ANNOTATION_BASE_TYPE = 'wandb.annotation';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useEffect, useMemo, useState} from 'react';

import {useBaseObjectInstances} from '../../pages/wfReactInterface/baseObjectClassQuery';
import {useBaseObjectInstances} from '../../pages/wfReactInterface/objectClassQuery';
import {
TraceObjQueryReq,
TraceObjSchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import {CellValue} from '../../../Browse2/CellValue';
import {NotApplicable} from '../../../Browse2/NotApplicable';
import {SmallRef} from '../../../Browse2/SmallRef';
import {StyledDataGrid} from '../../StyledDataGrid'; // Import the StyledDataGrid component
import {WEAVE_REF_SCHEME} from '../wfReactInterface/constants';
import {useWFHooks} from '../wfReactInterface/context';
import {
TraceObjSchemaForBaseObjectClass,
useBaseObjectInstances,
} from '../wfReactInterface/baseObjectClassQuery';
import {WEAVE_REF_SCHEME} from '../wfReactInterface/constants';
import {useWFHooks} from '../wfReactInterface/context';
} from '../wfReactInterface/objectClassQuery';
import {useGetTraceServerClientContext} from '../wfReactInterface/traceServerClientContext';
import {Feedback} from '../wfReactInterface/traceServerClientTypes';
import {projectIdFromParts} from '../wfReactInterface/tsDataModelHooks';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {SimplePageLayout} from '../common/SimplePageLayout';
import {ObjectVersionsTable} from '../ObjectVersionsPage';
import {
useBaseObjectInstances,
useCreateBaseObjectInstance,
} from '../wfReactInterface/baseObjectClassQuery';
useCreateBuiltinObjectInstance,
} from '../wfReactInterface/objectClassQuery';
import {sanitizeObjectId} from '../wfReactInterface/traceServerDirectClient';
import {
convertTraceServerObjectVersionToSchema,
Expand Down Expand Up @@ -162,7 +162,8 @@ const generateLeaderboardId = () => {
};

const useCreateLeaderboard = (entity: string, project: string) => {
const createLeaderboardInstance = useCreateBaseObjectInstance('Leaderboard');
const createLeaderboardInstance =
useCreateBuiltinObjectInstance('Leaderboard');

const createLeaderboard = async () => {
const objectId = sanitizeObjectId(generateLeaderboardId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import {LeaderboardObjectVal} from '../../views/Leaderboard/types/leaderboardCon
import {SimplePageLayout} from '../common/SimplePageLayout';
import {
useBaseObjectInstances,
useCreateBaseObjectInstance,
} from '../wfReactInterface/baseObjectClassQuery';
useCreateBuiltinObjectInstance,
} from '../wfReactInterface/objectClassQuery';
import {projectIdFromParts} from '../wfReactInterface/tsDataModelHooks';
import {LeaderboardConfigEditor} from './LeaderboardConfigEditor';

Expand Down Expand Up @@ -131,7 +131,7 @@ const useUpdateLeaderboard = (
project: string,
objectId: string
) => {
const createLeaderboard = useCreateBaseObjectInstance('Leaderboard');
const createLeaderboard = useCreateBuiltinObjectInstance('Leaderboard');

const updateLeaderboard = async (leaderboardVal: LeaderboardObjectVal) => {
return await createLeaderboard({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Box} from '@material-ui/core';
import React, {FC, useCallback, useEffect, useState} from 'react';
import {z} from 'zod';

import {createBaseObjectInstance} from '../wfReactInterface/baseObjectClassQuery';
import {createBuiltinObjectInstance} from '../wfReactInterface/objectClassQuery';
import {TraceServerClient} from '../wfReactInterface/traceServerClient';
import {sanitizeObjectId} from '../wfReactInterface/traceServerDirectClient';
import {projectIdFromParts} from '../wfReactInterface/tsDataModelHooks';
Expand Down Expand Up @@ -86,7 +86,7 @@ export const onAnnotationScorerSave = async (
) => {
const jsonSchemaType = convertTypeToJsonSchemaType(data.Type.type);
const typeExtras = convertTypeExtrasToJsonSchema(data);
return createBaseObjectInstance(client, 'AnnotationSpec', {
return createBuiltinObjectInstance(client, 'AnnotationSpec', {
obj: {
project_id: projectIdFromParts({entity, project}),
object_id: sanitizeObjectId(data.Name),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import _ from 'lodash';
import React, {FC, useCallback, useState} from 'react';
import {z} from 'zod';

import {LlmJudgeActionSpecSchema} from '../wfReactInterface/baseObjectClasses.zod';
import {createBaseObjectInstance} from '../wfReactInterface/baseObjectClassQuery';
import {ActionSpecSchema} from '../wfReactInterface/generatedBaseObjectClasses.zod';
import {LlmJudgeActionSpecSchema} from '../wfReactInterface/builtinObjectClasses.zod';
import {ActionSpecSchema} from '../wfReactInterface/generatedBuiltinObjectClasses.zod';
import {createBuiltinObjectInstance} from '../wfReactInterface/objectClassQuery';
import {TraceServerClient} from '../wfReactInterface/traceServerClient';
import {projectIdFromParts} from '../wfReactInterface/tsDataModelHooks';
import {AutocompleteWithLabel} from './FormComponents';
Expand Down Expand Up @@ -185,7 +185,7 @@ export const onLLMJudgeScorerSave = async (
config: judgeAction,
});

return createBaseObjectInstance(client, 'ActionSpec', {
return createBuiltinObjectInstance(client, 'ActionSpec', {
obj: {
project_id: projectIdFromParts({entity, project}),
object_id: objectId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* This file contains zod schemas for our baseObjectClasses that are not
* This file contains zod schemas for our builtinObjectClasses that are not
* correctly / completely generated by the json-schema to zod converter.
*/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,18 @@ export const TestOnlyExampleSchema = z.object({
});
export type TestOnlyExample = z.infer<typeof TestOnlyExampleSchema>;

export const baseObjectClassRegistry = {
export const builtinObjectClassRegistry = {
ActionSpec: ActionSpecSchema,
AnnotationSpec: AnnotationSpecSchema,
Leaderboard: LeaderboardSchema,
TestOnlyExample: TestOnlyExampleSchema,
TestOnlyNestedBaseObject: TestOnlyNestedBaseObjectSchema,
};

export const GeneratedBaseObjectClassesZodSchema = z.object(
baseObjectClassRegistry
export const GeneratedBuiltinObjectClassesZodSchema = z.object(
builtinObjectClassRegistry
);

export type GeneratedBaseObjectClassesZod = z.infer<
typeof GeneratedBaseObjectClassesZodSchema
export type GeneratedBuiltinObjectClassesZod = z.infer<
typeof GeneratedBuiltinObjectClassesZodSchema
>;
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {expectType} from 'tsd';

import {
useBaseObjectInstances,
useCreateBaseObjectInstance,
} from './baseObjectClassQuery';
import {
TestOnlyExample,
TestOnlyExampleSchema,
} from './generatedBaseObjectClasses.zod';
} from './generatedBuiltinObjectClasses.zod';
import {
useBaseObjectInstances,
useCreateBuiltinObjectInstance,
} from './objectClassQuery';
import {
TraceObjCreateReq,
TraceObjCreateRes,
Expand Down Expand Up @@ -74,7 +74,7 @@ describe('Type Tests', () => {

it('useCreateCollectionObject return type matches expected structure', () => {
type CreateCollectionObjectReturn = ReturnType<
typeof useCreateBaseObjectInstance<'TestOnlyExample'>
typeof useCreateBuiltinObjectInstance<'TestOnlyExample'>
>;

// Define the expected type structure
Expand Down
Loading
Loading