From 55ff66b6b1f797e3a43d21dd08ce815da13acb1d Mon Sep 17 00:00:00 2001 From: "zoo-github-actions-auth[bot]" Date: Tue, 18 Nov 2025 13:35:39 +0000 Subject: [PATCH 1/2] YOYO NEW API SPEC! --- spec.json | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/spec.json b/spec.json index e8ceb644e..60df1f68c 100644 --- a/spec.json +++ b/spec.json @@ -30957,6 +30957,31 @@ ], "additionalProperties": false }, + { + "description": "Notification that the KCL project has been updated.", + "type": "object", + "properties": { + "project_updated": { + "type": "object", + "properties": { + "files": { + "description": "Map of file paths to their latest contents. The file contents are not encoded since kcl files are not binary.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "files" + ] + } + }, + "required": [ + "project_updated" + ], + "additionalProperties": false + }, { "description": "Assistant reasoning / chain-of-thought (if you expose it).", "type": "object", @@ -30971,7 +30996,7 @@ "additionalProperties": false }, { - "description": "Replay containing raw bytes for previously-saved messages for a conversation. Includes server messages and client `User` messages.\n\nInvariants: - Includes server messages: `Info`, `Error`, `Reasoning(..)`, `ToolOutput { .. }`, and `EndOfStream { .. }`. - Also includes client `User` messages. - The following are NEVER included: `SessionData`, `ConversationId`, or `Delta`. - Ordering is stable: messages are ordered by prompt creation time within the conversation, then by the per-prompt `seq` value (monotonically increasing as seen in the original stream).\n\nWire format: - Each element is canonical serialized bytes (typically JSON) for either a `MlCopilotServerMessage` or a `MlCopilotClientMessage::User`. - When delivered as an initial replay over the websocket (upon `?replay=true&conversation_id=`), the server sends a single WebSocket Binary frame containing a BSON-encoded document of this enum: `Replay { messages }`.", + "description": "Replay containing raw bytes for previously-saved messages for a conversation. Includes server messages and client `User` messages.\n\nInvariants: - Includes server messages: `Info`, `Error`, `Reasoning(..)`, `ToolOutput { .. }`, `ProjectUpdated { .. }`, and `EndOfStream { .. }`. - Also includes client `User` messages. - The following are NEVER included: `SessionData`, `ConversationId`, or `Delta`. - Ordering is stable: messages are ordered by prompt creation time within the conversation, then by the per-prompt `seq` value (monotonically increasing as seen in the original stream).\n\nWire format: - Each element is canonical serialized bytes (typically JSON) for either a `MlCopilotServerMessage` or a `MlCopilotClientMessage::User`. - When delivered as an initial replay over the websocket (upon `?replay=true&conversation_id=`), the server sends a single WebSocket Binary frame containing a BSON-encoded document of this enum: `Replay { messages }`.", "type": "object", "properties": { "replay": { From ecb056ee9096957c447f082d98f0a5d0993a2010 Mon Sep 17 00:00:00 2001 From: "zoo-github-actions-auth[bot]" Date: Tue, 18 Nov 2025 13:36:24 +0000 Subject: [PATCH 2/2] I have generated the latest API! --- kittycad.py.patch.json | 2 +- kittycad/models/ml_copilot_server_message.py | 29 ++++++++++++++++++-- kittycad/tests/test_examples.py | 12 ++++---- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/kittycad.py.patch.json b/kittycad.py.patch.json index 4fe748e18..e2b202d0f 100644 --- a/kittycad.py.patch.json +++ b/kittycad.py.patch.json @@ -179,7 +179,7 @@ "op": "add", "path": "/paths/~1file~1conversion/post/x-python", "value": { - "example": "from kittycad.models.conversion_params import ConversionParams\nfrom kittycad.models.output_format3d import OptionPly\nfrom kittycad.models.system import System\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.selection import OptionDefaultScene\nfrom kittycad.models.selection import Selection\nfrom kittycad.models.ply_storage import PlyStorage\nfrom kittycad.models.unit_length import UnitLength\nfrom kittycad.models.output_format3d import OutputFormat3d\nfrom kittycad.models.input_format3d import OptionSldprt\nfrom kittycad.models.input_format3d import InputFormat3d\nfrom pathlib import Path\nfrom typing import Dict\nfrom kittycad._io_types import SyncUpload\nfrom kittycad.models import FileConversion\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_create_file_conversion_options():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n result: FileConversion = client.file.create_file_conversion_options(body=ConversionParams(\n output_format=OutputFormat3d(OptionPly(\n coords=System(\n forward=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n up=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n ),\n selection=Selection(OptionDefaultScene()),\n storage=PlyStorage.ASCII,\n units=UnitLength.CM,\n )),\n src_format=InputFormat3d(OptionSldprt(\n split_closed_faces=False,\n )),\n ),\n file_attachments={\n \"main.kcl\": Path(\"path/to/main.kcl\"),\n \"helper.kcl\": Path(\"path/to/helper.kcl\"),\n })\n\n\n body: FileConversion = result\n print(body)\n\n", + "example": "from kittycad.models.conversion_params import ConversionParams\nfrom kittycad.models.output_format3d import OptionStl\nfrom kittycad.models.system import System\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.selection import OptionDefaultScene\nfrom kittycad.models.selection import Selection\nfrom kittycad.models.stl_storage import StlStorage\nfrom kittycad.models.unit_length import UnitLength\nfrom kittycad.models.output_format3d import OutputFormat3d\nfrom kittycad.models.input_format3d import OptionSldprt\nfrom kittycad.models.input_format3d import InputFormat3d\nfrom pathlib import Path\nfrom typing import Dict\nfrom kittycad._io_types import SyncUpload\nfrom kittycad.models import FileConversion\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_create_file_conversion_options():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n result: FileConversion = client.file.create_file_conversion_options(body=ConversionParams(\n output_format=OutputFormat3d(OptionStl(\n coords=System(\n forward=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n up=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n ),\n selection=Selection(OptionDefaultScene()),\n storage=StlStorage.ASCII,\n units=UnitLength.CM,\n )),\n src_format=InputFormat3d(OptionSldprt(\n split_closed_faces=False,\n )),\n ),\n file_attachments={\n \"main.kcl\": Path(\"path/to/main.kcl\"),\n \"helper.kcl\": Path(\"path/to/helper.kcl\"),\n })\n\n\n body: FileConversion = result\n print(body)\n\n", "libDocsLink": "https://python.api.docs.zoo.dev/_autosummary/kittycad.KittyCAD.html#kittycad.KittyCAD.file" } }, diff --git a/kittycad/models/ml_copilot_server_message.py b/kittycad/models/ml_copilot_server_message.py index d2c1dfa4d..fc46ba6af 100644 --- a/kittycad/models/ml_copilot_server_message.py +++ b/kittycad/models/ml_copilot_server_message.py @@ -1,5 +1,5 @@ import datetime -from typing import List, Optional, Union +from typing import Dict, List, Optional, Union from pydantic import RootModel, model_serializer, model_validator @@ -151,6 +151,30 @@ def _wrap(self, handler, info): return {"info": payload} +class ProjectUpdated(KittyCadBaseModel): + """Notification that the KCL project has been updated.""" + + files: Dict[str, str] + + @model_validator(mode="before") + @classmethod + def _unwrap(cls, data): + if ( + isinstance(data, dict) + and "project_updated" in data + and isinstance(data["project_updated"], dict) + ): + return data["project_updated"] + + return data + + @model_serializer(mode="wrap") + def _wrap(self, handler, info): + payload = handler(self, info) + + return {"project_updated": payload} + + class Reasoning(KittyCadBaseModel): """Assistant reasoning / chain-of-thought (if you expose it).""" @@ -160,7 +184,7 @@ class Reasoning(KittyCadBaseModel): class Replay(KittyCadBaseModel): """Replay containing raw bytes for previously-saved messages for a conversation. Includes server messages and client `User` messages. - Invariants: - Includes server messages: `Info`, `Error`, `Reasoning(..)`, `ToolOutput { .. }`, and `EndOfStream { .. }`. - Also includes client `User` messages. - The following are NEVER included: `SessionData`, `ConversationId`, or `Delta`. - Ordering is stable: messages are ordered by prompt creation time within the conversation, then by the per-prompt `seq` value (monotonically increasing as seen in the original stream). + Invariants: - Includes server messages: `Info`, `Error`, `Reasoning(..)`, `ToolOutput { .. }`, `ProjectUpdated { .. }`, and `EndOfStream { .. }`. - Also includes client `User` messages. - The following are NEVER included: `SessionData`, `ConversationId`, or `Delta`. - Ordering is stable: messages are ordered by prompt creation time within the conversation, then by the per-prompt `seq` value (monotonically increasing as seen in the original stream). Wire format: - Each element is canonical serialized bytes (typically JSON) for either a `MlCopilotServerMessage` or a `MlCopilotClientMessage::User`. - When delivered as an initial replay over the websocket (upon `?replay=true&conversation_id=`), the server sends a single WebSocket Binary frame containing a BSON-encoded document of this enum: `Replay { messages }`.""" @@ -225,6 +249,7 @@ def _wrap(self, handler, info): ToolOutput, Error, Info, + ProjectUpdated, Reasoning, Replay, EndOfStream, diff --git a/kittycad/tests/test_examples.py b/kittycad/tests/test_examples.py index 4ae81a412..5b893adc6 100644 --- a/kittycad/tests/test_examples.py +++ b/kittycad/tests/test_examples.py @@ -107,9 +107,8 @@ from kittycad.models.modeling_app_event_type import ModelingAppEventType from kittycad.models.org_dataset_source import OrgDatasetSource from kittycad.models.org_details import OrgDetails -from kittycad.models.output_format3d import OptionPly, OutputFormat3d +from kittycad.models.output_format3d import OptionStl, OutputFormat3d from kittycad.models.plan_interval import PlanInterval -from kittycad.models.ply_storage import PlyStorage from kittycad.models.post_effect_type import PostEffectType from kittycad.models.privacy_settings import PrivacySettings from kittycad.models.rtc_ice_candidate_init import RtcIceCandidateInit @@ -120,6 +119,7 @@ from kittycad.models.source_position import SourcePosition from kittycad.models.source_range import SourceRange from kittycad.models.source_range_prompt import SourceRangePrompt +from kittycad.models.stl_storage import StlStorage from kittycad.models.storage_provider import StorageProvider from kittycad.models.store_coupon_params import StoreCouponParams from kittycad.models.subscribe import Subscribe @@ -627,7 +627,7 @@ def test_create_file_conversion_options(): result: FileConversion = client.file.create_file_conversion_options( body=ConversionParams( output_format=OutputFormat3d( - OptionPly( + OptionStl( coords=System( forward=AxisDirectionPair( axis=Axis.Y, @@ -639,7 +639,7 @@ def test_create_file_conversion_options(): ), ), selection=Selection(OptionDefaultScene()), - storage=PlyStorage.ASCII, + storage=StlStorage.ASCII, units=UnitLength.CM, ) ), @@ -668,7 +668,7 @@ async def test_create_file_conversion_options_async(): result: FileConversion = await client.file.create_file_conversion_options( body=ConversionParams( output_format=OutputFormat3d( - OptionPly( + OptionStl( coords=System( forward=AxisDirectionPair( axis=Axis.Y, @@ -680,7 +680,7 @@ async def test_create_file_conversion_options_async(): ), ), selection=Selection(OptionDefaultScene()), - storage=PlyStorage.ASCII, + storage=StlStorage.ASCII, units=UnitLength.CM, ) ),